summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bsps/arm/atsam/console/console.c476
-rw-r--r--bsps/arm/atsam/i2c/atsam_i2c_bus.c146
-rw-r--r--bsps/arm/atsam/include/bsp.h13
-rw-r--r--bsps/arm/atsam/include/bsp/atsam-i2c.h32
-rw-r--r--bsps/arm/headers.am4
-rw-r--r--bsps/arm/imx/start/bspstart.c61
-rw-r--r--bsps/arm/include/bsp/arm-cp15-start.h6
-rw-r--r--bsps/arm/include/bsp/cadence-spi-regs.h84
-rw-r--r--bsps/arm/include/bsp/cadence-spi.h63
-rw-r--r--bsps/arm/include/bsp/linker-symbols.h4
-rw-r--r--bsps/arm/include/bsp/xilinx-axi-spi-regs.h88
-rw-r--r--bsps/arm/include/bsp/xilinx-axi-spi.h67
-rw-r--r--bsps/arm/include/bsp/zynq-uart.h7
-rw-r--r--bsps/arm/shared/serial/zynq-uart-polled.c2
-rw-r--r--bsps/arm/shared/serial/zynq-uart.c77
-rw-r--r--bsps/arm/shared/spi/cadence-spi.c444
-rw-r--r--bsps/arm/shared/spi/xilinx-axi-spi.c402
-rw-r--r--bsps/headers.am1
-rw-r--r--bsps/i386/pc386/clock/ckinit.c71
-rw-r--r--bsps/include/bsp/irq-default.h6
-rw-r--r--bsps/include/bsp/irq-generic.h42
-rw-r--r--bsps/include/bsp/irq-info.h35
-rw-r--r--bsps/include/grlib/ahbstat.h2
-rw-r--r--bsps/include/grlib/ambapp_ids.h19
-rw-r--r--bsps/include/grlib/canbtrs.h94
-rw-r--r--bsps/include/grlib/grcan.h130
-rw-r--r--bsps/include/grlib/greth.h1
-rw-r--r--bsps/include/grlib/grlib_impl.h10
-rw-r--r--bsps/include/grlib/grspw_pkt.h4
-rw-r--r--bsps/include/grlib/grspw_router.h1
-rw-r--r--bsps/include/grlib/occan.h2
-rw-r--r--bsps/m68k/uC5282/start/linkcmds34
-rw-r--r--bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c145
-rw-r--r--bsps/powerpc/beatnik/net/if_mve/testing.c324
-rw-r--r--bsps/powerpc/beatnik/net/porting/if_xxx.modini.c34
-rw-r--r--bsps/powerpc/include/bsp/irq_supp.h5
-rw-r--r--bsps/powerpc/include/libcpu/io.h8
-rw-r--r--bsps/powerpc/motorola_powerpc/bootloader/misc.c4
-rw-r--r--bsps/powerpc/motorola_powerpc/bootloader/ppcboot.lds10
-rw-r--r--bsps/powerpc/motorola_powerpc/include/bsp.h34
-rw-r--r--bsps/powerpc/motorola_powerpc/include/bsp/irq.h15
-rw-r--r--bsps/powerpc/motorola_powerpc/start/bspstart.c7
-rw-r--r--bsps/powerpc/shared/irq/i8259.c152
-rw-r--r--bsps/powerpc/shared/irq/irq_init.c17
-rw-r--r--bsps/powerpc/shared/irq/openpic_i8259_irq.c29
-rw-r--r--bsps/powerpc/shared/irq/ppc-irq-generic.c117
-rw-r--r--bsps/shared/grlib-sources.am3
-rw-r--r--bsps/shared/grlib/1553/gr1553b.c4
-rw-r--r--bsps/shared/grlib/1553/gr1553bc.c76
-rw-r--r--bsps/shared/grlib/1553/gr1553bm.c49
-rw-r--r--bsps/shared/grlib/1553/gr1553rt.c123
-rw-r--r--bsps/shared/grlib/amba/ahbstat.c8
-rw-r--r--bsps/shared/grlib/amba/ambapp_names.c21
-rw-r--r--bsps/shared/grlib/btimer/tlib_ckinit.c7
-rw-r--r--bsps/shared/grlib/can/canbtrs.c144
-rw-r--r--bsps/shared/grlib/can/grcan.c719
-rw-r--r--bsps/shared/grlib/can/grcan_internal.h140
-rw-r--r--bsps/shared/grlib/can/grcanfd.c535
-rw-r--r--bsps/shared/grlib/can/grcanstd.c435
-rw-r--r--bsps/shared/grlib/can/occan.c151
-rw-r--r--bsps/shared/grlib/irq/genirq.c4
-rw-r--r--bsps/shared/grlib/l2c/l2c.c4
-rw-r--r--bsps/shared/grlib/net/greth.c22
-rw-r--r--bsps/shared/grlib/spw/grspw.c7
-rw-r--r--bsps/shared/grlib/spw/grspw_router.c5
-rw-r--r--bsps/shared/irq/irq-default-handler.c40
-rw-r--r--bsps/shared/irq/irq-default.c12
-rw-r--r--bsps/shared/irq/irq-generic.c36
-rw-r--r--bsps/shared/irq/irq-info.c35
-rw-r--r--bsps/shared/irq/irq-legacy.c35
-rw-r--r--bsps/shared/irq/irq-lock.c36
-rw-r--r--bsps/shared/irq/irq-server.c27
-rw-r--r--bsps/shared/irq/irq-shell.c35
-rw-r--r--bsps/sparc/leon3/start/amba.c12
-rw-r--r--bsps/sparc/leon3/start/cpucounter.c5
-rw-r--r--bsps/sparc/leon3/start/drvmgr_def_drivers.c28
-rw-r--r--c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am4
-rw-r--r--c/src/lib/libbsp/arm/xilinx-zynqmp/Makefile.am4
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am5
-rw-r--r--c/src/lib/libbsp/sparc/leon3/Makefile.am1
-rw-r--r--cpukit/Makefile.am5
-rw-r--r--cpukit/headers.am1
-rw-r--r--cpukit/include/link_elf.h8
-rw-r--r--cpukit/include/linux/rbtree.h10
-rw-r--r--cpukit/include/rtems/capture.h4
-rw-r--r--cpukit/include/rtems/confdefs/percpu.h18
-rw-r--r--cpukit/include/rtems/confdefs/wkspace.h16
-rw-r--r--cpukit/include/rtems/config.h3
-rw-r--r--cpukit/include/rtems/linkersets.h2
-rw-r--r--cpukit/include/rtems/posix/muteximpl.h7
-rw-r--r--cpukit/include/rtems/posix/pthreadattrimpl.h2
-rw-r--r--cpukit/include/rtems/rtl/rtl-obj.h20
-rw-r--r--cpukit/include/rtems/rtl/rtl.h2
-rw-r--r--cpukit/include/rtems/score/corebarrierimpl.h9
-rw-r--r--cpukit/include/rtems/score/cpustdatomic.h6
-rw-r--r--cpukit/include/rtems/score/heapimpl.h10
-rw-r--r--cpukit/include/rtems/score/objectimpl.h29
-rw-r--r--cpukit/include/rtems/score/priority.h4
-rw-r--r--cpukit/include/rtems/score/priorityimpl.h2
-rw-r--r--cpukit/include/rtems/score/scheduleredfimpl.h4
-rw-r--r--cpukit/include/rtems/score/stack.h24
-rw-r--r--cpukit/include/rtems/score/threadq.h13
-rw-r--r--cpukit/include/rtems/score/threadqops.h134
-rw-r--r--cpukit/include/rtems/score/timecounter.h24
-rw-r--r--cpukit/include/rtems/score/tls.h2
-rw-r--r--cpukit/include/rtems/score/watchdogimpl.h2
-rw-r--r--cpukit/include/rtems/shellconfig.h28
-rw-r--r--cpukit/include/rtems/termiostypes.h6
-rw-r--r--cpukit/include/rtems/version.h21
-rw-r--r--cpukit/libcsupport/src/posix_devctl.c80
-rw-r--r--cpukit/libcsupport/src/sync.c93
-rw-r--r--cpukit/libcsupport/src/termios.c5
-rw-r--r--cpukit/libfs/src/imfs/imfs_memfile.c3
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt.c8
-rw-r--r--cpukit/libmisc/shell/main_chmod.c2
-rw-r--r--cpukit/libmisc/shell/main_edit.c18
-rw-r--r--cpukit/libmisc/shell/main_i2cdetect.c107
-rw-r--r--cpukit/libmisc/shell/main_i2cget.c145
-rw-r--r--cpukit/libmisc/shell/main_i2cset.c124
-rw-r--r--cpukit/libmisc/shell/main_spi.c157
-rw-r--r--cpukit/libmisc/untar/untar.c57
-rw-r--r--cpukit/posix/src/nanosleep.c31
-rw-r--r--cpukit/rtems/src/ratemoncreate.c1
-rw-r--r--cpukit/rtems/src/semcreate.c7
-rw-r--r--cpukit/rtems/src/taskstart.c4
-rw-r--r--cpukit/score/cpu/sparc/cpu_asm.S11
-rw-r--r--cpukit/score/cpu/sparc/sparc-access.S4
-rw-r--r--cpukit/score/cpu/sparc/sparc-counter-asm.S3
-rw-r--r--cpukit/score/cpu/sparc/syscall.S3
-rw-r--r--cpukit/score/src/corebarrierrelease.c3
-rw-r--r--cpukit/score/src/corebarrierwait.c32
-rw-r--r--cpukit/score/src/heapallocate.c9
-rw-r--r--cpukit/score/src/kern_tc.c676
-rw-r--r--cpukit/score/src/objectactivecount.c18
-rw-r--r--cpukit/score/src/objectfree.c12
-rw-r--r--cpukit/score/src/stackallocatorforidle.c59
-rw-r--r--cpukit/score/src/threadcreateidle.c12
-rw-r--r--cpukit/score/src/threadqops.c27
-rw-r--r--testsuites/libtests/malloctest/init.c4
-rw-r--r--testsuites/libtests/tar01/init.c199
-rw-r--r--testsuites/libtests/tar01/tar01.doc1
-rw-r--r--testsuites/libtests/tar01/tar01.scn54
-rw-r--r--testsuites/libtests/tar01/tar01.tarbin10240 -> 10240 bytes
-rw-r--r--testsuites/psxtests/psxdevctl01/test.c69
-rw-r--r--testsuites/psxtests/psximfs02/init.c30
-rw-r--r--testsuites/sptests/Makefile.am18
-rw-r--r--testsuites/sptests/configure.ac2
-rw-r--r--testsuites/sptests/spmrsp01/init.c6
-rw-r--r--testsuites/sptests/spstkalloc03/init.c103
-rw-r--r--testsuites/sptests/spstkalloc03/spstkalloc03.doc19
-rw-r--r--testsuites/sptests/spstkalloc03/spstkalloc03.scn2
-rw-r--r--testsuites/sptests/spstkalloc04/init.c82
-rw-r--r--testsuites/sptests/spstkalloc04/spstkalloc04.doc20
-rw-r--r--testsuites/sptests/spstkalloc04/spstkalloc04.scn2
-rw-r--r--testsuites/sptests/sptask_err04/task1.c9
-rw-r--r--testsuites/sptests/sptimecounter01/init.c4
156 files changed, 6385 insertions, 2467 deletions
diff --git a/bsps/arm/atsam/console/console.c b/bsps/arm/atsam/console/console.c
index d51d2ace7d..0802ca2155 100644
--- a/bsps/arm/atsam/console/console.c
+++ b/bsps/arm/atsam/console/console.c
@@ -16,6 +16,7 @@
#include <bsp/irq.h>
#include <bsp/fatal.h>
#include <rtems/console.h>
+#include <rtems/seterr.h>
#include <rtems/termiostypes.h>
@@ -23,274 +24,92 @@
#include <unistd.h>
+#define UART_RX_DMA_BUF_SIZE 32l
+
+typedef struct {
+ char buf[UART_RX_DMA_BUF_SIZE];
+ LinkedListDescriporView3 desc;
+} atsam_uart_rx_dma;
+
typedef struct {
rtems_termios_device_context base;
- Usart *regs;
+ Uart *regs;
rtems_vector_number irq;
uint32_t id;
bool console;
+ bool is_usart;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
bool transmitting;
+ bool rx_dma_enabled;
+ uint32_t rx_dma_channel;
+ atsam_uart_rx_dma *rx_dma;
+ char *volatile*rx_dma_da;
+ char *rx_next_read_pos;
#endif
-} atsam_usart_context;
+} atsam_uart_context;
-static atsam_usart_context atsam_usart_instances[] = {
+static atsam_uart_context atsam_usart_instances[] = {
{
- .regs = USART0,
+ .regs = (Uart *)USART0,
.irq = USART0_IRQn,
- .id = ID_USART0
+ .id = ID_USART0,
+ .is_usart = true,
}
#ifdef USART1
, {
- .regs = USART1,
+ .regs = (Uart *)USART1,
.irq = USART1_IRQn,
- .id = ID_USART1
+ .id = ID_USART1,
+ .is_usart = true,
}
#endif
#ifdef USART2
, {
- .regs = USART2,
+ .regs = (Uart *)USART2,
.irq = USART2_IRQn,
- .id = ID_USART2
- }
-#endif
-};
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
-static void atsam_usart_interrupt(void *arg)
-{
- rtems_termios_tty *tty = arg;
- atsam_usart_context *ctx = rtems_termios_get_device_context(tty);
- Usart *regs = ctx->regs;
- uint32_t csr = regs->US_CSR;
-
- while ((csr & US_CSR_RXRDY) != 0) {
- char c = (char) regs->US_RHR;
-
- rtems_termios_enqueue_raw_characters(tty, &c, 1);
-
- csr = regs->US_CSR;
- }
-
- if (ctx->transmitting && (csr & US_CSR_TXEMPTY) != 0) {
- rtems_termios_dequeue_characters(tty, 1);
- }
-}
-#endif
-
-static bool atsam_usart_set_attributes(
- rtems_termios_device_context *base,
- const struct termios *term
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
- rtems_termios_baud_t baud;
- uint32_t mr;
-
- baud = rtems_termios_baud_to_number(term->c_ospeed);
- regs->US_BRGR = (BOARD_MCK / baud) / 16;
-
- if ((term->c_cflag & CREAD) != 0) {
- regs->US_CR = US_CR_RXEN | US_CR_TXEN;
- } else {
- regs->US_CR = US_CR_TXEN;
- }
-
- mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
-
- switch (term->c_cflag & CSIZE) {
- case CS5:
- mr |= US_MR_CHRL_5_BIT;
- break;
- case CS6:
- mr |= US_MR_CHRL_6_BIT;
- break;
- case CS7:
- mr |= US_MR_CHRL_7_BIT;
- break;
- default:
- mr |= US_MR_CHRL_8_BIT;
- break;
- }
-
- if ((term->c_cflag & PARENB) != 0) {
- if ((term->c_cflag & PARODD) != 0) {
- mr |= US_MR_PAR_ODD;
- } else {
- mr |= US_MR_PAR_EVEN;
- }
- } else {
- mr |= US_MR_PAR_NO;
- }
-
- if ((term->c_cflag & CSTOPB) != 0) {
- mr |= US_MR_NBSTOP_2_BIT;
- } else {
- mr |= US_MR_NBSTOP_1_BIT;
- }
-
- regs->US_MR = mr;
-
- return true;
-}
-
-static bool atsam_usart_first_open(
- rtems_termios_tty *tty,
- rtems_termios_device_context *base,
- struct termios *term,
- rtems_libio_open_close_args_t *args
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- rtems_status_code sc;
-#endif
-
- regs->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RSTSTA;
- regs->US_IDR = 0xffffffff;
-
- PMC_EnablePeripheral(ctx->id);
-
- rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
- atsam_usart_set_attributes(base, term);
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- regs->US_IER = US_IDR_RXRDY;
- sc = rtems_interrupt_handler_install(
- ctx->irq,
- "USART",
- RTEMS_INTERRUPT_SHARED,
- atsam_usart_interrupt,
- tty
- );
- if (sc != RTEMS_SUCCESSFUL) {
- return false;
- }
-#endif
-
- return true;
-}
-
-static void atsam_usart_last_close(
- rtems_termios_tty *tty,
- rtems_termios_device_context *base,
- rtems_libio_open_close_args_t *args
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- rtems_interrupt_handler_remove(ctx->irq, atsam_usart_interrupt, tty);
-#endif
-
- if (!ctx->console) {
- PMC_DisablePeripheral(ctx->id);
- }
-}
-
-static void atsam_usart_write(
- rtems_termios_device_context *base,
- const char *buf,
- size_t len
-)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- if (len > 0) {
- ctx->transmitting = true;
- regs->US_THR = buf[0];
- regs->US_IER = US_IDR_TXEMPTY;
- } else {
- ctx->transmitting = false;
- regs->US_IDR = US_IDR_TXEMPTY;
- }
-#else
- size_t i;
-
- for (i = 0; i < len; ++i) {
- while ((regs->US_CSR & US_CSR_TXEMPTY) == 0) {
- /* Wait */
- }
-
- regs->US_THR = buf[i];
+ .id = ID_USART2,
+ .is_usart = true,
}
#endif
-}
-
-#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
-static int atsam_usart_read(rtems_termios_device_context *base)
-{
- atsam_usart_context *ctx = (atsam_usart_context *) base;
- Usart *regs = ctx->regs;
-
- if ((regs->US_CSR & US_CSR_RXRDY) != 0) {
- return (char) regs->US_RHR;
- } else {
- return -1;
- }
-}
-#endif
-
-static const rtems_termios_device_handler atsam_usart_handler = {
- .first_open = atsam_usart_first_open,
- .last_close = atsam_usart_last_close,
- .write = atsam_usart_write,
- .set_attributes = atsam_usart_set_attributes,
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- .mode = TERMIOS_IRQ_DRIVEN
-#else
- .poll_read = atsam_usart_read,
- .mode = TERMIOS_POLLED
-#endif
};
-typedef struct {
- rtems_termios_device_context base;
- Uart *regs;
- rtems_vector_number irq;
- uint32_t id;
- bool console;
-#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- bool transmitting;
-#endif
-} atsam_uart_context;
-
static atsam_uart_context atsam_uart_instances[] = {
{
.regs = UART0,
.irq = UART0_IRQn,
- .id = ID_UART0
+ .id = ID_UART0,
+ .is_usart = false,
}
#ifdef UART1
, {
.regs = UART1,
.irq = UART1_IRQn,
- .id = ID_UART1
+ .id = ID_UART1,
+ .is_usart = false,
}
#endif
#ifdef UART2
, {
.regs = UART2,
.irq = UART2_IRQn,
- .id = ID_UART2
+ .id = ID_UART2,
+ .is_usart = false,
}
#endif
#ifdef UART3
, {
.regs = UART3,
.irq = UART3_IRQn,
- .id = ID_UART3
+ .id = ID_UART3,
+ .is_usart = false,
}
#endif
#ifdef UART4
, {
.regs = UART4,
.irq = UART4_IRQn,
- .id = ID_UART4
+ .id = ID_UART4,
+ .is_usart = false,
}
#endif
};
@@ -303,16 +122,32 @@ static void atsam_uart_interrupt(void *arg)
Uart *regs = ctx->regs;
uint32_t sr = regs->UART_SR;
- while ((sr & UART_SR_RXRDY) != 0) {
- char c = (char) regs->UART_RHR;
+ if (!ctx->rx_dma_enabled) {
+ while ((sr & UART_SR_RXRDY) != 0) {
+ char c = (char) regs->UART_RHR;
- rtems_termios_enqueue_raw_characters(tty, &c, 1);
+ rtems_termios_enqueue_raw_characters(tty, &c, 1);
- sr = regs->UART_SR;
+ sr = regs->UART_SR;
+ }
+ } else {
+ while (*ctx->rx_dma_da != ctx->rx_next_read_pos) {
+ char c;
+
+ c = *ctx->rx_next_read_pos;
+
+ ++ctx->rx_next_read_pos;
+ if (ctx->rx_next_read_pos >= &ctx->rx_dma->buf[UART_RX_DMA_BUF_SIZE]) {
+ ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
+ }
+
+ rtems_termios_enqueue_raw_characters(tty, &c, 1);
+ }
}
- if (ctx->transmitting && (sr & UART_SR_TXEMPTY) != 0) {
+ while (ctx->transmitting && (sr & UART_SR_TXRDY) != 0) {
rtems_termios_dequeue_characters(tty, 1);
+ sr = regs->UART_SR;
}
}
#endif
@@ -336,10 +171,31 @@ static bool atsam_uart_set_attributes(
regs->UART_CR = UART_CR_TXEN;
}
- mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
-
- if ((term->c_cflag & CSIZE) != CS8) {
- return false;
+ if (ctx->is_usart) {
+ mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
+ } else {
+ mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
+ }
+
+ if (ctx->is_usart) {
+ switch (term->c_cflag & CSIZE) {
+ case CS5:
+ mr |= US_MR_CHRL_5_BIT;
+ break;
+ case CS6:
+ mr |= US_MR_CHRL_6_BIT;
+ break;
+ case CS7:
+ mr |= US_MR_CHRL_7_BIT;
+ break;
+ default:
+ mr |= US_MR_CHRL_8_BIT;
+ break;
+ }
+ } else {
+ if ((term->c_cflag & CSIZE) != CS8) {
+ return false;
+ }
}
if ((term->c_cflag & PARENB) != 0) {
@@ -352,8 +208,16 @@ static bool atsam_uart_set_attributes(
mr |= UART_MR_PAR_NO;
}
- if ((term->c_cflag & CSTOPB) != 0) {
- return false;
+ if (ctx->is_usart) {
+ if ((term->c_cflag & CSTOPB) != 0) {
+ mr |= US_MR_NBSTOP_2_BIT;
+ } else {
+ mr |= US_MR_NBSTOP_1_BIT;
+ }
+ } else {
+ if ((term->c_cflag & CSTOPB) != 0) {
+ return false;
+ }
}
regs->UART_MR = mr;
@@ -361,6 +225,118 @@ static bool atsam_uart_set_attributes(
return true;
}
+static void atsam_uart_disable_rx_dma(atsam_uart_context *ctx)
+{
+ if (ctx->rx_dma) {
+ rtems_cache_coherent_free(ctx->rx_dma);
+ ctx->rx_dma = NULL;
+ }
+
+ if (ctx->rx_dma_channel != XDMAD_ALLOC_FAILED) {
+ XDMAD_FreeChannel(&XDMAD_Instance, ctx->rx_dma_channel);
+ }
+
+ ctx->rx_dma_enabled = false;
+}
+
+static rtems_status_code atsam_uart_enable_rx_dma(atsam_uart_context *ctx)
+{
+ eXdmadRC rc;
+ int channel_id;
+
+ if (ctx->rx_dma_enabled) {
+ return RTEMS_SUCCESSFUL;
+ }
+
+ /*
+ * Make sure everything is in a clean default state so that the cleanup works
+ * in an error case.
+ */
+ ctx->rx_dma = NULL;
+ ctx->rx_dma_channel = XDMAD_ALLOC_FAILED;
+
+ ctx->rx_dma = rtems_cache_coherent_allocate(sizeof(*ctx->rx_dma), 0, 0);
+ if (ctx->rx_dma == NULL) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_NO_MEMORY;
+ }
+
+ ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
+
+ ctx->rx_dma_channel = XDMAD_AllocateChannel(
+ &XDMAD_Instance,
+ XDMAD_TRANSFER_MEMORY,
+ ctx->id
+ );
+
+ if (ctx->rx_dma_channel == XDMAD_ALLOC_FAILED) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ rc = XDMAD_PrepareChannel(&XDMAD_Instance, ctx->rx_dma_channel);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ channel_id = ctx->rx_dma_channel & 0xff;
+ ctx->rx_dma_da =
+ (char *volatile*) &XDMAD_Instance.pXdmacs->XDMAC_CHID[channel_id].XDMAC_CDA;
+
+ ctx->rx_dma->desc.mbr_nda = (uint32_t)&ctx->rx_dma->desc;
+ ctx->rx_dma->desc.mbr_ubc =
+ 1 |
+ XDMA_UBC_NVIEW_NDV3 |
+ XDMA_UBC_NDE_FETCH_EN |
+ XDMA_UBC_NDEN_UPDATED |
+ XDMA_UBC_NSEN_UPDATED;
+ ctx->rx_dma->desc.mbr_sa = (uint32_t) &ctx->regs->UART_RHR;
+ ctx->rx_dma->desc.mbr_da = (uint32_t) &ctx->rx_dma->buf[0];
+ ctx->rx_dma->desc.mbr_cfg =
+ XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_PER2MEM |
+ XDMAC_CC_SWREQ_HWR_CONNECTED |
+ XDMAC_CC_MEMSET_NORMAL_MODE |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_FIXED_AM |
+ XDMAC_CC_DAM_UBS_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ctx->id, XDMAD_TRANSFER_RX));
+ ctx->rx_dma->desc.mbr_bc = UART_RX_DMA_BUF_SIZE - 1;
+ ctx->rx_dma->desc.mbr_ds = 0;
+ ctx->rx_dma->desc.mbr_sus = 0;
+ ctx->rx_dma->desc.mbr_dus = 0;
+
+ rc = XDMAD_ConfigureTransfer(
+ &XDMAD_Instance,
+ ctx->rx_dma_channel,
+ NULL,
+ XDMAC_CNDC_NDE_DSCR_FETCH_EN |
+ XDMAC_CNDC_NDVIEW_NDV3 |
+ XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
+ XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED,
+ (uint32_t)&ctx->rx_dma->desc,
+ 0);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ rc = XDMAD_StartTransfer(&XDMAD_Instance, ctx->rx_dma_channel);
+ if (rc != XDMAD_OK) {
+ atsam_uart_disable_rx_dma(ctx);
+ return RTEMS_IO_ERROR;
+ }
+
+ ctx->rx_dma_enabled = true;
+
+ return RTEMS_SUCCESSFUL;
+}
+
static bool atsam_uart_first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
@@ -386,7 +362,7 @@ static bool atsam_uart_first_open(
regs->UART_IER = UART_IDR_RXRDY;
sc = rtems_interrupt_handler_install(
ctx->irq,
- "UART",
+ ctx->is_usart ? "USART" : "UART",
RTEMS_INTERRUPT_SHARED,
atsam_uart_interrupt,
tty
@@ -411,6 +387,10 @@ static void atsam_uart_last_close(
rtems_interrupt_handler_remove(ctx->irq, atsam_uart_interrupt, tty);
#endif
+ if (ctx->rx_dma_enabled) {
+ atsam_uart_disable_rx_dma(ctx);
+ }
+
if (!ctx->console) {
PMC_DisablePeripheral(ctx->id);
}
@@ -429,16 +409,16 @@ static void atsam_uart_write(
if (len > 0) {
ctx->transmitting = true;
regs->UART_THR = buf[0];
- regs->UART_IER = UART_IDR_TXEMPTY;
+ regs->UART_IER = UART_IDR_TXRDY;
} else {
ctx->transmitting = false;
- regs->UART_IDR = UART_IDR_TXEMPTY;
+ regs->UART_IDR = UART_IDR_TXRDY;
}
#else
size_t i;
for (i = 0; i < len; ++i) {
- while ((regs->UART_SR & UART_SR_TXEMPTY) == 0) {
+ while ((regs->UART_SR & UART_SR_TXRDY) == 0) {
/* Wait */
}
@@ -461,13 +441,41 @@ static int atsam_uart_read(rtems_termios_device_context *base)
}
#endif
+#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
+static int atsam_uart_ioctl(
+ rtems_termios_device_context *base,
+ ioctl_command_t request,
+ void *buffer
+)
+{
+ atsam_uart_context *ctx = (atsam_uart_context *) base;
+ rtems_status_code sc;
+
+ switch (request) {
+ case ATSAM_UART_ENABLE_RX_DMA:
+ sc = atsam_uart_enable_rx_dma(ctx);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_set_errno_and_return_minus_one(EIO);
+ } else {
+ ctx->rx_dma_enabled = true;
+ }
+ break;
+ default:
+ rtems_set_errno_and_return_minus_one(EINVAL);
+ }
+
+ return 0;
+}
+#endif
+
static const rtems_termios_device_handler atsam_uart_handler = {
.first_open = atsam_uart_first_open,
.last_close = atsam_uart_last_close,
.write = atsam_uart_write,
.set_attributes = atsam_uart_set_attributes,
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
- .mode = TERMIOS_IRQ_DRIVEN
+ .mode = TERMIOS_IRQ_DRIVEN,
+ .ioctl = atsam_uart_ioctl,
#else
.poll_read = atsam_uart_read,
.mode = TERMIOS_POLLED
@@ -490,7 +498,7 @@ rtems_status_code console_initialize(
usart[sizeof(usart) - 2] = (char) ('0' + i);
rtems_termios_device_install(
&usart[0],
- &atsam_usart_handler,
+ &atsam_uart_handler,
NULL,
&atsam_usart_instances[i].base
);
diff --git a/bsps/arm/atsam/i2c/atsam_i2c_bus.c b/bsps/arm/atsam/i2c/atsam_i2c_bus.c
index 4425975de8..3451d15bed 100644
--- a/bsps/arm/atsam/i2c/atsam_i2c_bus.c
+++ b/bsps/arm/atsam/i2c/atsam_i2c_bus.c
@@ -33,72 +33,65 @@
static void
atsam_i2c_disable_interrupts(Twihs *regs)
{
- regs->TWIHS_IDR = 0xFFFFFFFF;
+ TWI_DisableIt(regs, 0xFFFFFFFF);
}
-static void
-atsam_i2c_set_transfer_status(transfer_desc *trans_desc, transfer_state state)
+/*
+ * Return true if the message is done right after this. That is the case if all
+ * bytes are received but no stop is requested.
+ */
+static bool
+atsam_i2c_continue_read(Twihs *regs, atsam_i2c_bus *bus)
{
- trans_desc->trans_state = state;
-}
+ bool done = false;
-static void
-atsam_i2c_continue_read(Twihs *regs, transfer_desc *trans_desc)
-{
- trans_desc->data[trans_desc->already_transferred] = TWI_ReadByte(regs);
- trans_desc->already_transferred++;
+ *bus->current_msg_byte = TWI_ReadByte(regs);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
/* check for transfer finish */
- if (trans_desc->already_transferred == trans_desc->data_size) {
- if (trans_desc->stop_request){
+ if (bus->current_msg_todo == 0) {
+ if (bus->stop_request){
TWI_DisableIt(regs, TWIHS_IDR_RXRDY);
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
- atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
- atsam_i2c_set_transfer_status(trans_desc, RX_CONT_MESSAGE_NEEDED);
+ done = true;
}
}
/* Last byte? */
- else if ((trans_desc->already_transferred == (trans_desc->data_size - 1))
- && (trans_desc->stop_request)){
+ else if (bus->current_msg_todo == 1 && bus->stop_request) {
TWI_Stop(regs);
}
+
+ return done;
}
+/*
+ * Return true if the message is done right after this. That is the case if all
+ * bytes are sent but no stop is requested.
+ */
static bool
-atsam_i2c_is_state(transfer_desc *trans_desc, transfer_state state)
+atsam_i2c_continue_write(Twihs *regs, atsam_i2c_bus *bus)
{
- return (trans_desc->trans_state == state);
-}
+ bool done = false;
-static void
-atsam_i2c_continue_write(Twihs *regs, transfer_desc *trans_desc)
-{
/* Transfer finished ? */
- if (trans_desc->already_transferred == trans_desc->data_size) {
+ if (bus->current_msg_todo == 0) {
TWI_DisableIt(regs, TWIHS_IDR_TXRDY);
- if (trans_desc->stop_request){
+ if (bus->stop_request){
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
TWI_SendSTOPCondition(regs);
- atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
- atsam_i2c_set_transfer_status(trans_desc, TX_CONT_MESSAGE_NEEDED);
+ done = true;
}
}
/* Bytes remaining */
else {
- TWI_WriteByte(regs,
- trans_desc->data[trans_desc->already_transferred]);
- trans_desc->already_transferred++;
+ TWI_WriteByte(regs, *bus->current_msg_byte);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
}
-}
-
-static void
-atsam_i2c_finish_write_transfer(Twihs *regs, transfer_desc *trans_desc)
-{
- TWI_ReadByte(regs);
- TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
- trans_desc->status = 0;
+ return done;
}
static void
@@ -115,19 +108,6 @@ atsam_i2c_next_packet(atsam_i2c_bus *bus)
bus->current_msg_byte = msg->buf;
}
-static void
-atsam_i2c_set_td(atsam_i2c_bus *bus, uint32_t already_transferred,
- bool stop_needed)
-{
- transfer_desc *trans_desc = &bus->trans_desc;
-
- trans_desc->status = ASYNC_STATUS_PENDING;
- trans_desc->data = bus->current_msg_byte;
- trans_desc->data_size = bus->current_msg_todo;
- trans_desc->already_transferred = already_transferred;
- trans_desc->stop_request = stop_needed;
-}
-
static bool
atsam_i2c_set_address_size(const i2c_msg *msg)
{
@@ -186,6 +166,8 @@ atsam_i2c_setup_write_transfer(atsam_i2c_bus *bus, Twihs *regs, bool ctrl,
{
atsam_i2c_set_address_regs(regs, slave_addr, ctrl, false);
TWI_WriteByte(regs, *bus->current_msg_byte);
+ ++bus->current_msg_byte;
+ --bus->current_msg_todo;
TWI_EnableIt(regs, TWIHS_IER_TXRDY);
}
@@ -197,8 +179,8 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
uint32_t msg_todo = bus->msg_todo;
uint16_t slave_addr;
bool ten_bit_addr = false;
- uint32_t already_transferred;
bool stop_needed = true;
+ bool read;
ten_bit_addr = atsam_i2c_set_address_size(msgs);
@@ -206,22 +188,17 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
stop_needed = false;
}
- bus->read = (msgs->flags & I2C_M_RD) != 0;
+ read = (msgs->flags & I2C_M_RD) != 0;
slave_addr = msgs->addr;
- already_transferred = (bus->read == true) ? 0 : 1;
- atsam_i2c_set_td(bus, already_transferred, stop_needed);
-
- transfer_desc *trans_desc = &bus->trans_desc;
+ bus->stop_request = stop_needed;
- if (bus->read){
+ if (read){
if (bus->current_msg_todo == 1){
send_stop = true;
}
- atsam_i2c_set_transfer_status(trans_desc, RX_SEND_DATA);
atsam_i2c_setup_read_transfer(regs, ten_bit_addr,
slave_addr, send_stop);
} else {
- atsam_i2c_set_transfer_status(trans_desc, TX_SEND_DATA);
atsam_i2c_setup_write_transfer(bus, regs, ten_bit_addr,
slave_addr);
}
@@ -233,40 +210,28 @@ atsam_i2c_interrupt(void *arg)
atsam_i2c_bus *bus = arg;
uint32_t irqstatus;
bool done = false;
- transfer_desc *trans_desc;
Twihs *regs = bus->regs;
/* read interrupts */
- irqstatus = regs->TWIHS_SR;
+ irqstatus = TWI_GetMaskedStatus(regs);
- if((irqstatus & (TWIHS_SR_ARBLST | TWIHS_SR_NACK)) != 0) {
+ if((irqstatus & ATSAMV_I2C_IRQ_ERROR) != 0) {
done = true;
- }
-
- trans_desc = &bus->trans_desc;
-
- if (((irqstatus & TWIHS_SR_RXRDY) != 0) &&
- (atsam_i2c_is_state(trans_desc, RX_SEND_DATA))){
- /* carry on read transfer */
- atsam_i2c_continue_read(regs, trans_desc);
- } else if (((irqstatus & TWIHS_SR_TXCOMP) != 0) &&
- (atsam_i2c_is_state(trans_desc, TX_RX_STOP_SENT))){
- atsam_i2c_finish_write_transfer(regs, trans_desc);
+ } else if ((irqstatus & TWIHS_SR_RXRDY) != 0) {
+ done = atsam_i2c_continue_read(regs, bus);
+ } else if ((irqstatus & TWIHS_SR_TXCOMP) != 0) {
+ TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
done = true;
- } else if (((irqstatus & TWIHS_SR_TXRDY) != 0) &&
- (atsam_i2c_is_state(trans_desc, TX_SEND_DATA))){
- atsam_i2c_continue_write(regs, trans_desc);
- if (trans_desc->trans_state == TX_CONT_MESSAGE_NEEDED){
- done = true;
- }
+ } else if ((irqstatus & TWIHS_SR_TXRDY) != 0) {
+ done = atsam_i2c_continue_write(regs, bus);
}
if(done){
- uint32_t err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
+ bus->err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
atsam_i2c_next_packet(bus);
- if (bus->msg_todo == 0 || err != 0) {
+ if (bus->msg_todo == 0 || bus->err != 0) {
atsam_i2c_disable_interrupts(regs);
rtems_binary_semaphore_post(&bus->sem);
} else {
@@ -291,27 +256,38 @@ atsam_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
return -EINVAL;
}
+ if (msgs[i].len == 0) {
+ /* Hardware doesn't support zero length messages */
+ return -EINVAL;
+ }
}
bus->msgs = &msgs[0];
bus->msg_todo = msg_count;
bus->current_msg_todo = msgs[0].len;
bus->current_msg_byte = msgs[0].buf;
+ bus->err = 0;
regs = bus->regs;
- atsam_i2c_setup_transfer(bus, regs);
+ /* Start with a clean start. Enable error interrupts. */
+ TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
+ TWI_EnableIt(regs, ATSAMV_I2C_IRQ_ERROR);
- regs->TWIHS_IER = ATSAMV_I2C_IRQ_ERROR;
+ atsam_i2c_setup_transfer(bus, regs);
eno = rtems_binary_semaphore_wait_timed_ticks(
&bus->sem,
bus->base.timeout
);
- if (eno != 0) {
+ if (eno != 0 || bus->err != 0) {
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
rtems_binary_semaphore_try_wait(&bus->sem);
- return -ETIMEDOUT;
+ if (bus->err != 0) {
+ return -EIO;
+ } else {
+ return -ETIMEDOUT;
+ }
}
return 0;
diff --git a/bsps/arm/atsam/include/bsp.h b/bsps/arm/atsam/include/bsp.h
index 2556f6046d..d1b021255c 100644
--- a/bsps/arm/atsam/include/bsp.h
+++ b/bsps/arm/atsam/include/bsp.h
@@ -33,6 +33,7 @@
#include <bspopts.h>
#include <bsp/default-initial-extension.h>
+#include <sys/ioccom.h>
#include <rtems.h>
@@ -109,6 +110,18 @@ void atsam_rtc_get_time(rtems_time_of_day *tod);
void bsp_restart( const void *const addr );
+/*
+ * This ioctl enables the receive DMA for an UART. The DMA can be usefull if you
+ * loose characters in high interrupt load situations.
+ *
+ * Disabling the DMA again is only possible by closing all file descriptors of
+ * that UART.
+ *
+ * Note that every UART needs one DMA channel and the system has only a limited
+ * amount of DMAs. So only use it if you need it.
+ */
+#define ATSAM_UART_ENABLE_RX_DMA _IO('d', 0)
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/bsps/arm/atsam/include/bsp/atsam-i2c.h b/bsps/arm/atsam/include/bsp/atsam-i2c.h
index ae0fe97584..a6a9c27d48 100644
--- a/bsps/arm/atsam/include/bsp/atsam-i2c.h
+++ b/bsps/arm/atsam/include/bsp/atsam-i2c.h
@@ -28,35 +28,23 @@ extern "C" {
#define TWI_AMOUNT_PINS 2
-typedef enum {
- TX_SEND_DATA,
- TX_SEND_STOP,
- TX_CONT_MESSAGE_NEEDED,
- RX_SEND_DATA,
- RX_SEND_STOP,
- RX_CONT_MESSAGE_NEEDED,
- TX_RX_STOP_SENT
-}transfer_state;
-
-typedef struct {
- uint8_t status;
- uint8_t *data;
- bool stop_request;
- uint32_t data_size;
- uint32_t already_transferred;
- transfer_state trans_state;
-} transfer_desc;
-
typedef struct {
i2c_bus base;
- i2c_msg *msgs;
Twihs *regs;
- transfer_desc trans_desc;
+
+ /* First message and number of messages that have to be processed. */
+ i2c_msg *msgs;
uint32_t msg_todo;
+
+ /* Information about the current transfer. */
+ bool stop_request;
uint32_t current_msg_todo;
uint8_t *current_msg_byte;
+
+ /* Error information that can be returned to the task */
+ uint32_t err;
+
uint32_t output_clock;
- bool read;
rtems_binary_semaphore sem;
rtems_vector_number irq;
} atsam_i2c_bus;
diff --git a/bsps/arm/headers.am b/bsps/arm/headers.am
index 3d2b09effa..69a154f6b2 100644
--- a/bsps/arm/headers.am
+++ b/bsps/arm/headers.am
@@ -39,6 +39,10 @@ include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/lpc-timer.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/start.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart-regs.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart.h
+include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi-regs.h
+include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi.h
+include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi-regs.h
+include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi.h
include_libcpudir = $(includedir)/libcpu
include_libcpu_HEADERS =
diff --git a/bsps/arm/imx/start/bspstart.c b/bsps/arm/imx/start/bspstart.c
index 36f62993a6..07cf33a5ed 100644
--- a/bsps/arm/imx/start/bspstart.c
+++ b/bsps/arm/imx/start/bspstart.c
@@ -18,6 +18,7 @@
#include <bsp/fdt.h>
#include <bsp/irq-generic.h>
#include <bsp/linker-symbols.h>
+#include <libcpu/arm-cp15.h>
#include <libfdt.h>
@@ -58,6 +59,60 @@ uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
return intr[1] + MAGIC_IRQ_OFFSET;
}
+static bool imx_is_imx6(const void *fdt)
+{
+ /*
+ * At the moment: Check for some compatible strings that should be there
+ * somewhere in every fdt.
+ *
+ * FIXME: It would be nice if some CPU-ID could be used instead. But I didn't
+ * find one.
+ */
+ int node;
+
+ node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul");
+ if (node >= 0) {
+ return true;
+ }
+
+ node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ull");
+ if (node >= 0) {
+ return true;
+ }
+
+ return false;
+}
+
+#define SYSCNT_CNTCR (0x0)
+#define SYSCNT_CNTCR_ENABLE (1 << 0)
+#define SYSCNT_CNTCR_HDBG (1 << 1)
+#define SYSCNT_CNTCR_FCREQ(n) (1 << (8 + (n)))
+#define SYSCNT_CNTFID(n) (0x20 + 4 * (n))
+
+static uint32_t imx_syscnt_enable_and_return_frequency(const void *fdt)
+{
+ uint32_t freq;
+ volatile void *syscnt_base;
+
+ /* That's not in the usual FDTs. Sorry for falling back to a magic value. */
+ if (imx_is_imx6(fdt)) {
+ syscnt_base = (void *)0x021dc000;
+ } else {
+ syscnt_base = (void *)0x306c0000;
+ }
+
+ freq = *(uint32_t *)(syscnt_base + SYSCNT_CNTFID(0));
+
+ arm_cp15_set_counter_frequency(freq);
+
+ *(uint32_t *)(syscnt_base + SYSCNT_CNTCR) =
+ SYSCNT_CNTCR_ENABLE |
+ SYSCNT_CNTCR_HDBG |
+ SYSCNT_CNTCR_FCREQ(0);
+
+ return freq;
+}
+
void arm_generic_timer_get_config(
uint32_t *frequency,
uint32_t *irq
@@ -75,7 +130,11 @@ void arm_generic_timer_get_config(
if (val != NULL && len >= 4) {
*frequency = fdt32_to_cpu(val[0]);
} else {
- bsp_fatal(IMX_FATAL_GENERIC_TIMER_FREQUENCY);
+ /*
+ * Normally clock-frequency would be provided by the boot loader. If it
+ * didn't add one, we have to initialize the system counter ourself.
+ */
+ *frequency = imx_syscnt_enable_and_return_frequency(fdt);
}
/* FIXME: Figure out how Linux gets a proper IRQ number */
diff --git a/bsps/arm/include/bsp/arm-cp15-start.h b/bsps/arm/include/bsp/arm-cp15-start.h
index 86c4f8afcb..75cbdac848 100644
--- a/bsps/arm/include/bsp/arm-cp15-start.h
+++ b/bsps/arm/include/bsp/arm-cp15-start.h
@@ -74,6 +74,10 @@ typedef struct {
.end = (uint32_t) bsp_section_bss_end, \
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
}, { \
+ .begin = (uint32_t) bsp_section_rtemsstack_begin, \
+ .end = (uint32_t) bsp_section_rtemsstack_end, \
+ .flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
+ }, { \
.begin = (uint32_t) bsp_section_work_begin, \
.end = (uint32_t) bsp_section_work_end, \
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
@@ -95,7 +99,7 @@ typedef struct {
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
}
-#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 8
+#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 9
BSP_START_DATA_SECTION extern const arm_cp15_start_section_config
arm_cp15_start_mmu_config_table[];
diff --git a/bsps/arm/include/bsp/cadence-spi-regs.h b/bsps/arm/include/bsp/cadence-spi-regs.h
new file mode 100644
index 0000000000..b4b2366b3d
--- /dev/null
+++ b/bsps/arm/include/bsp/cadence-spi-regs.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
+#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
+
+#include <bsp/utility.h>
+
+typedef struct {
+ uint32_t config;
+#define CADENCE_SPI_CONFIG_MODEFAIL_EN BSP_BIT32(17)
+#define CADENCE_SPI_CONFIG_MANSTRT BSP_BIT32(16)
+#define CADENCE_SPI_CONFIG_MANSTRT_EN BSP_BIT32(15)
+#define CADENCE_SPI_CONFIG_MANUAL_CS BSP_BIT32(14)
+#define CADENCE_SPI_CONFIG_CS(val) BSP_FLD32(val, 10, 13)
+#define CADENCE_SPI_CONFIG_CS_GET(reg) BSP_FLD32GET(reg, 10, 13)
+#define CADENCE_SPI_CONFIG_CS_SET(reg, val) BSP_FLD32SET(reg, val, 10, 13)
+#define CADENCE_SPI_CONFIG_PERI_SEL BSP_BIT32(9)
+#define CADENCE_SPI_CONFIG_REF_CLK BSP_BIT32(8)
+#define CADENCE_SPI_CONFIG_BAUD_DIV(val) BSP_FLD32(val, 3, 5)
+#define CADENCE_SPI_CONFIG_BAUD_DIV_GET(reg) BSP_FLD32GET(reg, 3, 5)
+#define CADENCE_SPI_CONFIG_BAUD_DIV_SET(reg, val) BSP_FLD32SET(reg, val, 3, 5)
+#define CADENCE_SPI_CONFIG_CLK_PH BSP_BIT32(2)
+#define CADENCE_SPI_CONFIG_CLK_POL BSP_BIT32(1)
+#define CADENCE_SPI_CONFIG_MSTREN BSP_BIT32(0)
+ uint32_t irqstatus;
+ uint32_t irqenable;
+ uint32_t irqdisable;
+ uint32_t irqmask;
+#define CADENCE_SPI_IXR_TXUF BSP_BIT32(6)
+#define CADENCE_SPI_IXR_RXFULL BSP_BIT32(5)
+#define CADENCE_SPI_IXR_RXNEMPTY BSP_BIT32(4)
+#define CADENCE_SPI_IXR_TXFULL BSP_BIT32(3)
+#define CADENCE_SPI_IXR_TXOW BSP_BIT32(2)
+#define CADENCE_SPI_IXR_MODF BSP_BIT32(1)
+#define CADENCE_SPI_IXR_RXOVR BSP_BIT32(0)
+ uint32_t spienable;
+#define CADENCE_SPI_EN BSP_BIT32(0)
+ uint32_t delay;
+#define CADENCE_SPI_DELAY_DNSS(val) BSP_FLD32(val, 24, 31)
+#define CADENCE_SPI_DELAY_DNSS_GET(reg) BSP_FLD32GET(reg, 24, 31)
+#define CADENCE_SPI_DELAY_DNSS_SET(reg, val) BSP_FLD32SET(reg, val, 24, 31)
+#define CADENCE_SPI_DELAY_DBTWN(val) BSP_FLD32(val, 16, 23)
+#define CADENCE_SPI_DELAY_DBTWN_GET(reg) BSP_FLD32GET(reg, 16, 23)
+#define CADENCE_SPI_DELAY_DBTWN_SET(reg, val) BSP_FLD32SET(reg, val, 16, 23)
+#define CADENCE_SPI_DELAY_DAFTER(val) BSP_FLD32(val, 8, 15)
+#define CADENCE_SPI_DELAY_DAFTER_GET(reg) BSP_FLD32GET(reg, 8, 15)
+#define CADENCE_SPI_DELAY_DAFTER_SET(reg, val) BSP_FLD32SET(reg, val, 8, 15)
+#define CADENCE_SPI_DELAY_DINT(val) BSP_FLD32(val, 0, 7)
+#define CADENCE_SPI_DELAY_DINT_GET(reg) BSP_FLD32GET(reg, 0, 7)
+#define CADENCE_SPI_DELAY_DINT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7)
+ uint32_t txdata;
+ uint32_t rxdata;
+ uint32_t slave_idle_count;
+ uint32_t txthreshold;
+ uint32_t rxthreshold;
+ uint32_t moduleid;
+} cadence_spi;
+
+#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H */
diff --git a/bsps/arm/include/bsp/cadence-spi.h b/bsps/arm/include/bsp/cadence-spi.h
new file mode 100644
index 0000000000..d97ede53c8
--- /dev/null
+++ b/bsps/arm/include/bsp/cadence-spi.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
+#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Register the cadence-spi device with rtems
+ *
+ * @param bus_path path of the new device (e.g. /dev/spi0)
+ * @register_base Address of the first (i.e. config) register
+ * @input_clock Configured frequency of the input clock
+ *
+ * @return RTEMS_SUCCESSFUL on success, negative number on failure
+ *
+ * Note: The spi frequencies the cadence spi device can achieve
+ * are the @p input_clock divided by a power of 2 between
+ * 4 and 256.
+ * The driver tries to find a divider which yields a spi
+ * frequency equal to or lower than the desired bus frequency.
+ */
+int spi_bus_register_cadence(
+ const char *bus_path,
+ uintptr_t register_base,
+ uint32_t input_clock,
+ rtems_vector_number irq
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H */
diff --git a/bsps/arm/include/bsp/linker-symbols.h b/bsps/arm/include/bsp/linker-symbols.h
index d743f67f50..43651ff7f7 100644
--- a/bsps/arm/include/bsp/linker-symbols.h
+++ b/bsps/arm/include/bsp/linker-symbols.h
@@ -90,6 +90,10 @@ LINKER_SYMBOL(bsp_section_bss_begin)
LINKER_SYMBOL(bsp_section_bss_end)
LINKER_SYMBOL(bsp_section_bss_size)
+LINKER_SYMBOL(bsp_section_rtemsstack_begin)
+LINKER_SYMBOL(bsp_section_rtemsstack_end)
+LINKER_SYMBOL(bsp_section_rtemsstack_size)
+
LINKER_SYMBOL(bsp_section_work_begin)
LINKER_SYMBOL(bsp_section_work_end)
LINKER_SYMBOL(bsp_section_work_size)
diff --git a/bsps/arm/include/bsp/xilinx-axi-spi-regs.h b/bsps/arm/include/bsp/xilinx-axi-spi-regs.h
new file mode 100644
index 0000000000..6211c5b97f
--- /dev/null
+++ b/bsps/arm/include/bsp/xilinx-axi-spi-regs.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
+#define LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
+
+#include <bsp/utility.h>
+
+typedef struct {
+ uint32_t reserved1[7];
+ uint32_t globalirq;
+#define XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE BSP_BIT32(31)
+ uint32_t irqstatus;
+ uint32_t reserved2;
+ uint32_t irqenable;
+#define XILINX_AXI_SPI_IRQ_CMD_ERR BSP_BIT32(13)
+#define XILINX_AXI_SPI_IRQ_LOOP_ERR BSP_BIT32(12)
+#define XILINX_AXI_SPI_IRQ_MSB_ERR BSP_BIT32(11)
+#define XILINX_AXI_SPI_IRQ_SLV_ERR BSP_BIT32(10)
+#define XILINX_AXI_SPI_IRQ_CPOL_CPHA_ERR BSP_BIT32(9)
+#define XILINX_AXI_SPI_IRQ_RXNEMPTY BSP_BIT32(8)
+#define XILINX_AXI_SPI_IRQ_CS_MODE BSP_BIT32(7)
+#define XILINX_AXI_SPI_IRQ_TXHALF BSP_BIT32(6)
+#define XILINX_AXI_SPI_IRQ_RXOVR BSP_BIT32(5)
+#define XILINX_AXI_SPI_IRQ_RXFULL BSP_BIT32(4)
+#define XILINX_AXI_SPI_IRQ_TXUF BSP_BIT32(3)
+#define XILINX_AXI_SPI_IRQ_TXEMPTY BSP_BIT32(2)
+#define XILINX_AXI_SPI_IRQ_SLV_MODF BSP_BIT32(1)
+#define XILINX_AXI_SPI_IRQ_MODF BSP_BIT32(0)
+ uint32_t reserved3[5];
+ uint32_t reset;
+#define XILINX_AXI_SPI_RESET 0x0000000a
+ uint32_t reserved4[7];
+ uint32_t control;
+#define XILINX_AXI_SPI_CONTROL_LSBFIRST BSP_BIT32(9)
+#define XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT BSP_BIT32(8)
+#define XILINX_AXI_SPI_CONTROL_MANUAL_CS BSP_BIT32(7)
+#define XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET BSP_BIT32(6)
+#define XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET BSP_BIT32(5)
+#define XILINX_AXI_SPI_CONTROL_CPHA BSP_BIT32(4)
+#define XILINX_AXI_SPI_CONTROL_CPOL BSP_BIT32(3)
+#define XILINX_AXI_SPI_CONTROL_MSTREN BSP_BIT32(2)
+#define XILINX_AXI_SPI_CONTROL_SPIEN BSP_BIT32(1)
+#define XILINX_AXI_SPI_CONTROL_LOOP BSP_BIT32(0)
+ uint32_t status;
+#define XILINX_AXI_SPI_STATUS_CMD_ERR BSP_BIT32(10)
+#define XILINX_AXI_SPI_STATUS_LOOP_ERR BSP_BIT32(9)
+#define XILINX_AXI_SPI_STATUS_MSB_ERR BSP_BIT32(8)
+#define XILINX_AXI_SPI_STATUS_SLV_ERR BSP_BIT32(7)
+#define XILINX_AXI_SPI_STATUS_CPOL_CPHA_ERR BSP_BIT32(6)
+#define XILINX_AXI_SPI_STATUS_SLV_MODE BSP_BIT32(5)
+#define XILINX_AXI_SPI_STATUS_MODF BSP_BIT32(4)
+#define XILINX_AXI_SPI_STATUS_TXFULL BSP_BIT32(3)
+#define XILINX_AXI_SPI_STATUS_TXEMPTY BSP_BIT32(2)
+#define XILINX_AXI_SPI_STATUS_RXFULL BSP_BIT32(1)
+#define XILINX_AXI_SPI_STATUS_RXEMPTY BSP_BIT32(0)
+ uint32_t txdata;
+ uint32_t rxdata;
+ uint32_t cs;
+ uint32_t tx_fifo_len;
+ uint32_t rx_fifo_len;
+} xilinx_axi_spi;
+
+#endif /* LIBBSP_ARM_XILINX_AXI_SPI_REGS_H */
diff --git a/bsps/arm/include/bsp/xilinx-axi-spi.h b/bsps/arm/include/bsp/xilinx-axi-spi.h
new file mode 100644
index 0000000000..1f5e2a9989
--- /dev/null
+++ b/bsps/arm/include/bsp/xilinx-axi-spi.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_AXI_SPI_H
+#define LIBBSP_ARM_XILINX_AXI_SPI_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Register Xilinx AXI SPI device
+ *
+ * Note:
+ * The Xilinx Quad SPI device is very versatile and
+ * supports many options. This driver assumes the
+ * following setup:
+ * - Standard SPI mode and AXI Lite interface
+ * - FIFO available (driver might also work without FIFOs)
+ *
+ * @param bus_path path for the new device node (e.g. "/dev/spi0")
+ * @param register_base base address of the device
+ * @param fifo_size Configured fifo size. Either 0, 16 or 256
+ * @param num_cs Number of configured CS lines (0-32)
+ *
+ * @return 0 on success. Negative number otherwise.
+ *
+ */
+int spi_bus_register_xilinx_axi(
+ const char *bus_path,
+ uintptr_t register_base,
+ uint32_t fifo_size,
+ uint32_t num_cs,
+ rtems_vector_number irq
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_XILINX_AXI_SPI_H */
diff --git a/bsps/arm/include/bsp/zynq-uart.h b/bsps/arm/include/bsp/zynq-uart.h
index 20c3c9b653..5a6c926bec 100644
--- a/bsps/arm/include/bsp/zynq-uart.h
+++ b/bsps/arm/include/bsp/zynq-uart.h
@@ -71,6 +71,13 @@ void zynq_uart_write_polled(
*/
void zynq_uart_reset_tx_flush(zynq_uart_context *ctx);
+int zynq_cal_baud_rate(
+ uint32_t baudrate,
+ uint32_t* brgr,
+ uint32_t* bauddiv,
+ uint32_t modereg
+);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/bsps/arm/shared/serial/zynq-uart-polled.c b/bsps/arm/shared/serial/zynq-uart-polled.c
index e6f478ee07..7fc9590832 100644
--- a/bsps/arm/shared/serial/zynq-uart-polled.c
+++ b/bsps/arm/shared/serial/zynq-uart-polled.c
@@ -40,7 +40,7 @@ uint32_t zynq_uart_input_clock(void)
return ZYNQ_CLOCK_UART;
}
-static int zynq_cal_baud_rate(uint32_t baudrate,
+int zynq_cal_baud_rate(uint32_t baudrate,
uint32_t* brgr,
uint32_t* bauddiv,
uint32_t modereg)
diff --git a/bsps/arm/shared/serial/zynq-uart.c b/bsps/arm/shared/serial/zynq-uart.c
index fc670441b8..f298719fde 100644
--- a/bsps/arm/shared/serial/zynq-uart.c
+++ b/bsps/arm/shared/serial/zynq-uart.c
@@ -142,25 +142,82 @@ static bool zynq_uart_set_attributes(
const struct termios *term
)
{
-#if 0
- volatile zynq_uart *regs = zynq_uart_get_regs(minor);
+ zynq_uart_context *ctx = (zynq_uart_context *) context;
+ volatile zynq_uart *regs = ctx->regs;
+ int32_t baud;
uint32_t brgr = 0;
uint32_t bauddiv = 0;
+ uint32_t mode = 0;
int rc;
- rc = zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode);
- if (rc != 0)
- return rc;
+ /*
+ * Determine the baud rate
+ */
+ baud = rtems_termios_baud_to_number(term->c_ospeed);
+
+ if (baud > 0) {
+ rc = zynq_cal_baud_rate(baud, &brgr, &bauddiv, regs->mode);
+ if (rc != 0)
+ return rc;
+ }
+
+ /*
+ * Configure the mode register
+ */
+ mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
+
+ /*
+ * Parity
+ */
+ mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE);
+ if (term->c_cflag & PARENB) {
+ if (!(term->c_cflag & PARODD)) {
+ mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD);
+ } else {
+ mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN);
+ }
+ }
+
+ /*
+ * Character Size
+ */
+ switch (term->c_cflag & CSIZE)
+ {
+ case CS5:
+ return false;
+ case CS6:
+ mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6);
+ break;
+ case CS7:
+ mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7);
+ break;
+ case CS8:
+ default:
+ mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
+ break;
+ }
+
+ /*
+ * Stop Bits
+ */
+ if (term->c_cflag & CSTOPB) {
+ /* 2 stop bits */
+ mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2);
+ } else {
+ /* 1 stop bit */
+ mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
+ }
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
- regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
- regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
+ regs->mode = mode;
+ /* Ignore baud rate of B0. There are no modem control lines to de-assert */
+ if (baud > 0) {
+ regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
+ regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
+ }
regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
return true;
-#else
- return false;
-#endif
}
const rtems_termios_device_handler zynq_uart_handler = {
diff --git a/bsps/arm/shared/spi/cadence-spi.c b/bsps/arm/shared/spi/cadence-spi.c
new file mode 100644
index 0000000000..8e168d2e72
--- /dev/null
+++ b/bsps/arm/shared/spi/cadence-spi.c
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <bsp.h>
+
+#include <rtems/irq-extension.h>
+#include <sys/param.h> /* MAX() */
+
+#include <dev/spi/spi.h>
+#include <bsp/cadence-spi.h>
+#include <bsp/cadence-spi-regs.h>
+
+#define CADENCE_SPI_FIFO_SIZE 128
+#define CADENCE_SPI_MAX_CHIPSELECTS 3
+#define CADENCE_SPI_CS_NONE 0xF
+
+typedef struct cadence_spi_bus cadence_spi_bus;
+
+struct cadence_spi_bus {
+ spi_bus base;
+ volatile cadence_spi *regs;
+ uint32_t clk_in;
+ uint16_t clk_per_usecs;
+ uint32_t msg_todo;
+ const spi_ioc_transfer *msg;
+ uint32_t todo;
+ uint32_t in_transfer;
+ uint8_t *rx_buf;
+ const uint8_t *tx_buf;
+ rtems_id task_id;
+ rtems_vector_number irq;
+};
+
+
+static void cadence_spi_disable_interrupts(volatile cadence_spi *regs)
+{
+ regs->irqdisable = 0xffff;
+}
+
+static void cadence_spi_clear_irq_status(volatile cadence_spi *regs)
+{
+ regs->irqstatus = regs->irqstatus;
+}
+
+static bool cadence_spi_rx_fifo_not_empty(volatile cadence_spi *regs)
+{
+ return (regs->irqstatus & CADENCE_SPI_IXR_RXNEMPTY) != 0;
+}
+
+static void cadence_spi_reset(cadence_spi_bus *bus)
+{
+ volatile cadence_spi *regs = bus->regs;
+ uint32_t val;
+
+ cadence_spi_disable_interrupts(regs);
+
+ regs->spienable = 0;
+
+ val = regs->config;
+ val &= ~(CADENCE_SPI_CONFIG_MODEFAIL_EN
+ | CADENCE_SPI_CONFIG_MANSTRT_EN
+ | CADENCE_SPI_CONFIG_MANUAL_CS
+ | CADENCE_SPI_CONFIG_PERI_SEL
+ | CADENCE_SPI_CONFIG_REF_CLK);
+
+ val |= CADENCE_SPI_CONFIG_CS(CADENCE_SPI_CS_NONE)
+ | CADENCE_SPI_CONFIG_MSTREN
+ | CADENCE_SPI_CONFIG_MANSTRT;
+ regs->config = val;
+
+ /* Initialize here, will be set for every transfer */
+ regs->txthreshold = 1;
+ /* Set to 1, so we can check when the rx buffer is empty */
+ regs->rxthreshold = 1;
+
+ while (cadence_spi_rx_fifo_not_empty(regs)) {
+ regs->rxdata;
+ }
+ cadence_spi_clear_irq_status(regs);
+}
+
+static void cadence_spi_done(cadence_spi_bus *bus)
+{
+ volatile cadence_spi *regs = bus->regs;
+ regs->spienable = 0;
+ cadence_spi_disable_interrupts(regs);
+ cadence_spi_clear_irq_status(regs);
+ rtems_event_transient_send(bus->task_id);
+}
+
+static void cadence_spi_push(cadence_spi_bus *bus, volatile cadence_spi *regs)
+{
+ while (bus->todo > 0 && bus->in_transfer < CADENCE_SPI_FIFO_SIZE) {
+ uint8_t val = 0;
+ if (bus->tx_buf != NULL) {
+ val = *bus->tx_buf;
+ ++bus->tx_buf;
+ }
+
+ --bus->todo;
+ regs->txdata = val;
+ ++bus->in_transfer;
+ }
+}
+
+static void
+cadence_spi_set_chipsel(cadence_spi_bus *bus, uint32_t cs)
+{
+
+ volatile cadence_spi *regs = bus->regs;
+ uint32_t cs_bit = CADENCE_SPI_CS_NONE;
+ uint32_t config = regs->config;
+
+ if (cs != SPI_NO_CS && cs < CADENCE_SPI_MAX_CHIPSELECTS) {
+ cs_bit >>= (CADENCE_SPI_MAX_CHIPSELECTS - cs + 1);
+ }
+ config = CADENCE_SPI_CONFIG_CS_SET(config, cs_bit);
+ bus->base.cs = cs;
+
+ regs->config = config;
+}
+
+static uint32_t
+cadence_spi_baud_divider(cadence_spi_bus *bus,
+ uint32_t speed_hz)
+{
+ uint32_t div;
+ uint32_t clk_in;
+
+ clk_in = bus->clk_in;
+
+ div = clk_in / speed_hz;
+ div = fls((int) div);
+
+ if (clk_in > (speed_hz << div)) {
+ ++div;
+ }
+
+ /* The baud divider needs to be at least 4, i.e. 2^2 */
+ div = MAX(2, div);
+
+ /* 0b111 is the maximum possible divider value */
+ div = MIN(7, div-1);
+ return div;
+}
+
+static void cadence_spi_config(
+ cadence_spi_bus *bus,
+ volatile cadence_spi *regs,
+ uint32_t speed_hz,
+ uint32_t mode,
+ uint16_t delay_usecs,
+ uint8_t cs
+)
+{
+ spi_bus *base = &bus->base;
+ uint32_t config = regs->config;
+ uint32_t delay;
+
+ regs->spienable = 0;
+
+ if ((mode & SPI_CPHA) != 0) {
+ config |= CADENCE_SPI_CONFIG_CLK_PH;
+ } else {
+ config &= ~CADENCE_SPI_CONFIG_CLK_PH;
+ }
+
+ if ((mode & SPI_CPOL) != 0) {
+ config |= CADENCE_SPI_CONFIG_CLK_POL;
+ } else {
+ config &= ~CADENCE_SPI_CONFIG_CLK_POL;
+ }
+
+ config = CADENCE_SPI_CONFIG_BAUD_DIV_SET(config,
+ cadence_spi_baud_divider(bus, speed_hz));
+
+ regs->config = config;
+ cadence_spi_set_chipsel(bus, cs);
+
+ delay = regs->delay;
+ delay = CADENCE_SPI_DELAY_DBTWN_SET(delay, delay_usecs * bus->clk_per_usecs);
+ regs->delay = delay;
+
+ base->speed_hz = speed_hz;
+ base->mode = mode;
+ base->cs = cs;
+
+}
+
+static void
+cadence_spi_next_msg(cadence_spi_bus *bus, volatile cadence_spi *regs)
+{
+ if (bus->msg_todo > 0) {
+ const spi_ioc_transfer *msg;
+ spi_bus *base = &bus->base;
+
+ msg = bus->msg;
+
+ if (
+ msg->speed_hz != base->speed_hz
+ || msg->mode != base->mode
+ || msg->cs != base->cs
+ ) {
+ cadence_spi_config(
+ bus,
+ regs,
+ msg->speed_hz,
+ msg->mode,
+ msg->delay_usecs,
+ msg->cs
+ );
+ }
+
+ if ((msg->mode & SPI_NO_CS) != 0) {
+ cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
+ }
+
+ bus->todo = msg->len;
+ bus->rx_buf = msg->rx_buf;
+ bus->tx_buf = msg->tx_buf;
+ cadence_spi_push(bus, regs);
+
+ cadence_spi_disable_interrupts(regs);
+ if (bus->todo < CADENCE_SPI_FIFO_SIZE) {
+ /* if the msg fits into the FIFO for empty TX buffer */
+ regs->txthreshold = 1;
+
+ } else {
+ /* if the msg does not fit refill tx_buf when the threshold is hit */
+ regs->txthreshold = CADENCE_SPI_FIFO_SIZE / 2;
+ }
+ regs->irqenable = CADENCE_SPI_IXR_TXOW;
+ regs->spienable = 1;
+ } else {
+ cadence_spi_done(bus);
+ }
+}
+
+static void cadence_spi_interrupt(void *arg)
+{
+ cadence_spi_bus *bus;
+ volatile cadence_spi *regs;
+
+ bus = arg;
+ regs = bus->regs;
+
+ /* The RXNEMPTY flag is sometimes not cleared fast
+ * enough between 2 reads which could lead to
+ * reading an extra byte erroneously. Therefore,
+ * also check the in_transfer counter
+ */
+ while (cadence_spi_rx_fifo_not_empty(regs)
+ && bus->in_transfer > 0) {
+ uint32_t val = regs->rxdata;
+ if (bus->rx_buf != NULL) {
+ *bus->rx_buf = (uint8_t)val;
+ ++bus->rx_buf;
+ }
+ --bus->in_transfer;
+ }
+
+ if (bus->todo > 0) {
+ cadence_spi_push(bus, regs);
+ } else if (bus->in_transfer > 0) {
+ /* Wait until all bytes have been transfered */
+ regs->txthreshold = 1;
+ } else {
+ --bus->msg_todo;
+ ++bus->msg;
+ cadence_spi_next_msg(bus, regs);
+ }
+}
+
+static int cadence_spi_check_messages(
+ cadence_spi_bus *bus,
+ const spi_ioc_transfer *msg,
+ uint32_t size)
+{
+ while(size > 0) {
+ if (msg->bits_per_word != 8) {
+ return -EINVAL;
+ }
+ if ((msg->mode &
+ ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
+ return -EINVAL;
+ }
+ if ((msg->mode & SPI_NO_CS) == 0 &&
+ (msg->cs > CADENCE_SPI_MAX_CHIPSELECTS)) {
+ return -EINVAL;
+ }
+
+ ++msg;
+ --size;
+ }
+
+ return 0;
+}
+
+static int cadence_spi_transfer(
+ spi_bus *base,
+ const spi_ioc_transfer *msgs,
+ uint32_t n
+)
+{
+ cadence_spi_bus *bus;
+ int rv;
+
+ bus = (cadence_spi_bus *) base;
+
+ rv = cadence_spi_check_messages(bus, msgs, n);
+
+ if (rv == 0) {
+ bus->msg_todo = n;
+ bus->msg = &msgs[0];
+ bus->task_id = rtems_task_self();
+
+ cadence_spi_next_msg(bus, bus->regs);
+ rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
+ }
+ return rv;
+}
+
+static void cadence_spi_destroy(spi_bus *base)
+{
+ cadence_spi_bus *bus;
+
+ bus = (cadence_spi_bus *) base;
+ rtems_interrupt_handler_remove(bus->irq, cadence_spi_interrupt, bus);
+ spi_bus_destroy_and_free(&bus->base);
+}
+
+static int cadence_spi_setup(spi_bus *base)
+{
+ cadence_spi_bus *bus;
+ uint32_t mode = base->mode;
+
+ bus = (cadence_spi_bus *) base;
+
+ /* Baud rate divider is at least 4 and at most 256 */
+ if (
+ base->speed_hz > base->max_speed_hz
+ || base->speed_hz < (bus->clk_in / 256)
+ || bus->base.bits_per_word > 8
+ ) {
+ return -EINVAL;
+ }
+
+ /* SPI_CS_HIGH and SPI_LOOP not supported */
+ if ((mode & SPI_CS_HIGH) || (mode & SPI_LOOP)) {
+ return -EINVAL;
+ }
+
+ cadence_spi_config(
+ bus,
+ bus->regs,
+ base->speed_hz,
+ base->mode,
+ base->delay_usecs,
+ base->cs
+ );
+ return 0;
+}
+
+int spi_bus_register_cadence(const char *bus_path,
+ uintptr_t register_base,
+ uint32_t input_clock,
+ rtems_vector_number irq)
+{
+ cadence_spi_bus *bus;
+ spi_bus *base;
+ int sc;
+
+ bus = (cadence_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
+ if (bus == NULL){
+ return -1;
+ }
+
+ base = &bus->base;
+ bus->regs = (volatile cadence_spi *) register_base;
+ bus->clk_in = input_clock;
+ bus->clk_per_usecs = input_clock / 1000000;
+ bus->irq = irq;
+
+ /* The minimum clock divider is 4 */
+ base->max_speed_hz = (input_clock + 3) / 4;
+ base->delay_usecs = 0;
+ base->speed_hz = base->max_speed_hz;
+ base->cs = SPI_NO_CS;
+
+ cadence_spi_reset(bus);
+ cadence_spi_config(
+ bus,
+ bus->regs,
+ base->speed_hz,
+ base->mode,
+ base->delay_usecs,
+ base->cs
+ );
+
+
+ sc = rtems_interrupt_handler_install(
+ bus->irq,
+ "CASPI",
+ RTEMS_INTERRUPT_UNIQUE,
+ cadence_spi_interrupt,
+ bus
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->base.destroy)(&bus->base);
+ rtems_set_errno_and_return_minus_one(EAGAIN);
+ }
+
+ bus->base.transfer = cadence_spi_transfer;
+ bus->base.destroy = cadence_spi_destroy;
+ bus->base.setup = cadence_spi_setup;
+
+ return spi_bus_register(&bus->base, bus_path);
+}
diff --git a/bsps/arm/shared/spi/xilinx-axi-spi.c b/bsps/arm/shared/spi/xilinx-axi-spi.c
new file mode 100644
index 0000000000..7c4c9de8db
--- /dev/null
+++ b/bsps/arm/shared/spi/xilinx-axi-spi.c
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <bsp.h>
+
+#include <rtems/irq-extension.h>
+#include <sys/param.h> /* MAX() */
+
+#include <dev/spi/spi.h>
+#include <bsp/xilinx-axi-spi.h>
+#include <bsp/xilinx-axi-spi-regs.h>
+
+#define XILINX_AXI_SPI_CS_NONE 0xFF
+
+typedef struct xilinx_axi_spi_bus xilinx_axi_spi_bus;
+
+struct xilinx_axi_spi_bus {
+ spi_bus base;
+ volatile xilinx_axi_spi *regs;
+ uint32_t fifo_size;
+ uint32_t num_cs;
+ uint32_t msg_todo;
+ const spi_ioc_transfer *msg;
+ uint32_t todo;
+ uint32_t in_transfer;
+ uint8_t *rx_buf;
+ const uint8_t *tx_buf;
+ rtems_id task_id;
+ rtems_vector_number irq;
+};
+
+
+static void xilinx_axi_spi_disable_interrupts(volatile xilinx_axi_spi *regs)
+{
+ regs->globalirq = 0;
+ regs->irqenable = 0;
+}
+
+static bool xilinx_axi_spi_rx_fifo_not_empty(volatile xilinx_axi_spi *regs)
+{
+ return (regs->status & XILINX_AXI_SPI_STATUS_RXEMPTY) == 0;
+}
+
+static void xilinx_axi_spi_reset(xilinx_axi_spi_bus *bus)
+{
+ volatile xilinx_axi_spi *regs = bus->regs;
+ uint32_t control;
+
+ /* Initiate soft reset for initial state */
+ regs->reset = XILINX_AXI_SPI_RESET;
+
+ /* Configure as master */
+ control = regs->control;
+ control |= XILINX_AXI_SPI_CONTROL_MSTREN;
+ regs->control = control;
+}
+
+static void xilinx_axi_spi_done(xilinx_axi_spi_bus *bus)
+{
+ volatile xilinx_axi_spi *regs = bus->regs;
+ uint32_t control = regs->control;
+ control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
+ regs->control = control;
+
+ xilinx_axi_spi_disable_interrupts(regs);
+ rtems_event_transient_send(bus->task_id);
+}
+
+static void xilinx_axi_spi_push(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
+{
+ while (bus->todo > 0 && bus->in_transfer < bus->fifo_size) {
+ uint8_t val = 0;
+ if (bus->tx_buf != NULL) {
+ val = *bus->tx_buf;
+ ++bus->tx_buf;
+ }
+
+ --bus->todo;
+ regs->txdata = val;
+ ++bus->in_transfer;
+ }
+}
+
+static void
+xilinx_axi_spi_set_chipsel(xilinx_axi_spi_bus *bus, uint32_t cs)
+{
+
+ volatile xilinx_axi_spi *regs = bus->regs;
+ uint32_t cs_bit = XILINX_AXI_SPI_CS_NONE;
+
+ if (cs != SPI_NO_CS && cs < bus->num_cs) {
+ cs_bit &= ~(1<<cs);
+ }
+ bus->base.cs = cs;
+
+ regs->cs = cs_bit;
+}
+
+static void xilinx_axi_spi_config(
+ xilinx_axi_spi_bus *bus,
+ volatile xilinx_axi_spi *regs,
+ uint32_t mode,
+ uint8_t cs
+)
+{
+ spi_bus *base = &bus->base;
+ uint32_t control = regs->control;
+
+ control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
+ regs->control = control;
+
+ if ((mode & SPI_CPHA) != 0) {
+ control |= XILINX_AXI_SPI_CONTROL_CPHA;
+ } else {
+ control &= ~XILINX_AXI_SPI_CONTROL_CPHA;
+ }
+
+ if ((mode & SPI_CPOL) != 0) {
+ control |= XILINX_AXI_SPI_CONTROL_CPOL;
+ } else {
+ control &= ~XILINX_AXI_SPI_CONTROL_CPOL;
+ }
+
+ if ((mode & SPI_LOOP) != 0) {
+ control |= XILINX_AXI_SPI_CONTROL_LOOP;
+ } else {
+ control &= ~XILINX_AXI_SPI_CONTROL_LOOP;
+ }
+
+ regs->control = control;
+ xilinx_axi_spi_set_chipsel(bus, cs);
+
+ base->mode = mode;
+ base->cs = cs;
+
+}
+
+static void
+xilinx_axi_spi_next_msg(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
+{
+ uint32_t control = regs->control;
+ control |= XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT
+ | XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET
+ | XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET;
+ regs->control = control;
+
+ if (bus->msg_todo > 0) {
+ const spi_ioc_transfer *msg;
+ spi_bus *base = &bus->base;
+
+ msg = bus->msg;
+
+ if (
+ msg->mode != base->mode
+ || msg->cs != base->cs
+ ) {
+ xilinx_axi_spi_config(
+ bus,
+ regs,
+ msg->mode,
+ msg->cs
+ );
+ }
+
+ if ((msg->mode & SPI_NO_CS) != 0) {
+ xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
+ }
+
+ bus->todo = msg->len;
+ bus->rx_buf = msg->rx_buf;
+ bus->tx_buf = msg->tx_buf;
+ xilinx_axi_spi_push(bus, regs);
+
+ xilinx_axi_spi_disable_interrupts(regs);
+ if (
+ bus->todo < bus->fifo_size
+ || bus->fifo_size == 1) {
+ /* if the msg fits into the FIFO, wait for empty TX buffer */
+ regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
+
+ } else {
+ /* if the msg does not fit, refill tx_buf when the tx FIFO is half empty */
+ regs->irqenable = XILINX_AXI_SPI_IRQ_TXHALF;
+ }
+ regs->globalirq = XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE;
+ control = regs->control;
+ control |= XILINX_AXI_SPI_CONTROL_SPIEN;
+ control &= ~XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT;
+ regs->control = control;
+ } else {
+ xilinx_axi_spi_done(bus);
+ }
+}
+
+static void xilinx_axi_spi_interrupt(void *arg)
+{
+ xilinx_axi_spi_bus *bus;
+ volatile xilinx_axi_spi *regs;
+
+ bus = arg;
+ regs = bus->regs;
+
+ /* Clear interrupt flag. It's safe, since only one IRQ active at a time */
+ regs->irqstatus = regs->irqenable;
+
+ while (xilinx_axi_spi_rx_fifo_not_empty(regs)) {
+ uint32_t val = regs->rxdata;
+ if (bus->rx_buf != NULL) {
+ *bus->rx_buf = (uint8_t)val;
+ ++bus->rx_buf;
+ }
+ --bus->in_transfer;
+ }
+
+ if (bus->todo > 0) {
+ xilinx_axi_spi_push(bus, regs);
+ } else if (bus->in_transfer > 0) {
+ /* Wait until all bytes have been transfered */
+ regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
+ } else {
+ --bus->msg_todo;
+ ++bus->msg;
+ xilinx_axi_spi_next_msg(bus, regs);
+ }
+}
+
+static int xilinx_axi_spi_check_messages(
+ xilinx_axi_spi_bus *bus,
+ const spi_ioc_transfer *msg,
+ uint32_t size)
+{
+ while(size > 0) {
+ if (msg->bits_per_word != 8) {
+ return -EINVAL;
+ }
+ if ((msg->mode &
+ ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
+ return -EINVAL;
+ }
+ if ((msg->mode & SPI_NO_CS) == 0 &&
+ (msg->cs > bus->num_cs)) {
+ return -EINVAL;
+ }
+
+ ++msg;
+ --size;
+ }
+
+ return 0;
+}
+
+static int xilinx_axi_spi_transfer(
+ spi_bus *base,
+ const spi_ioc_transfer *msgs,
+ uint32_t n
+)
+{
+ xilinx_axi_spi_bus *bus;
+ int rv;
+
+ bus = (xilinx_axi_spi_bus *) base;
+
+ rv = xilinx_axi_spi_check_messages(bus, msgs, n);
+
+ if (rv == 0) {
+ bus->msg_todo = n;
+ bus->msg = &msgs[0];
+ bus->task_id = rtems_task_self();
+
+ xilinx_axi_spi_next_msg(bus, bus->regs);
+ rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
+ }
+ return rv;
+}
+
+static void xilinx_axi_spi_destroy(spi_bus *base)
+{
+ xilinx_axi_spi_bus *bus;
+
+ bus = (xilinx_axi_spi_bus *) base;
+ rtems_interrupt_handler_remove(bus->irq, xilinx_axi_spi_interrupt, bus);
+ spi_bus_destroy_and_free(&bus->base);
+}
+
+static int xilinx_axi_spi_setup(spi_bus *base)
+{
+ xilinx_axi_spi_bus *bus;
+ uint32_t mode = base->mode;
+
+ bus = (xilinx_axi_spi_bus *) base;
+
+ if (bus->base.bits_per_word > 8) {
+ return -EINVAL;
+ }
+
+ /* SPI_CS_HIGH not supported */
+ if (mode & SPI_CS_HIGH) {
+ return -EINVAL;
+ }
+
+ xilinx_axi_spi_config(
+ bus,
+ bus->regs,
+ base->mode,
+ base->cs
+ );
+ return 0;
+}
+
+int spi_bus_register_xilinx_axi(
+ const char *bus_path,
+ uintptr_t register_base,
+ uint32_t fifo_size,
+ uint32_t num_cs,
+ rtems_vector_number irq)
+{
+ xilinx_axi_spi_bus *bus;
+ spi_bus *base;
+ int sc;
+
+ if (fifo_size != 0 && fifo_size != 16 && fifo_size != 256) {
+ return -1;
+ }
+
+ if (num_cs > 32) {
+ return -1;
+ }
+
+ bus = (xilinx_axi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
+ if (bus == NULL){
+ return -1;
+ }
+
+ base = &bus->base;
+ bus->regs = (volatile xilinx_axi_spi *) register_base;
+ bus->irq = irq;
+ bus->num_cs = num_cs;
+
+ /* For operation without FIFO set fifo_size to 1
+ * so that comparison operators work
+ */
+ if (fifo_size == 0) {
+ bus->fifo_size = 1;
+ } else {
+ bus->fifo_size = fifo_size;
+ }
+
+ base->cs = SPI_NO_CS;
+
+ xilinx_axi_spi_reset(bus);
+ xilinx_axi_spi_config(
+ bus,
+ bus->regs,
+ base->mode,
+ base->cs
+ );
+
+
+ sc = rtems_interrupt_handler_install(
+ bus->irq,
+ "XSPI",
+ RTEMS_INTERRUPT_UNIQUE,
+ xilinx_axi_spi_interrupt,
+ bus
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ (*bus->base.destroy)(&bus->base);
+ rtems_set_errno_and_return_minus_one(EAGAIN);
+ }
+
+ bus->base.transfer = xilinx_axi_spi_transfer;
+ bus->base.destroy = xilinx_axi_spi_destroy;
+ bus->base.setup = xilinx_axi_spi_setup;
+
+ return spi_bus_register(&bus->base, bus_path);
+}
diff --git a/bsps/headers.am b/bsps/headers.am
index 5af7e43b4a..2c9b31df2b 100644
--- a/bsps/headers.am
+++ b/bsps/headers.am
@@ -34,6 +34,7 @@ include_grlib_HEADERS += ../../bsps/include/grlib/apbuart_termios.h
include_grlib_HEADERS += ../../bsps/include/grlib/b1553brm.h
include_grlib_HEADERS += ../../bsps/include/grlib/b1553rt.h
include_grlib_HEADERS += ../../bsps/include/grlib/bspcommon.h
+include_grlib_HEADERS += ../../bsps/include/grlib/canbtrs.h
include_grlib_HEADERS += ../../bsps/include/grlib/canmux.h
include_grlib_HEADERS += ../../bsps/include/grlib/cons.h
include_grlib_HEADERS += ../../bsps/include/grlib/debug_defs.h
diff --git a/bsps/i386/pc386/clock/ckinit.c b/bsps/i386/pc386/clock/ckinit.c
index 09afe73cde..2df1818dd3 100644
--- a/bsps/i386/pc386/clock/ckinit.c
+++ b/bsps/i386/pc386/clock/ckinit.c
@@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
/*
* Calibrate CPU cycles per tick. Interrupts should be disabled.
+ * Will also set the PIT, so call this before registering the
+ * periodic timer for rtems tick generation
*/
static void calibrate_tsc(void)
{
uint64_t begin_time;
- uint8_t then_lsb, then_msb, now_lsb, now_msb;
- uint32_t i;
-
- /*
- * We just reset the timer, so we know we're at the beginning of a tick.
- */
-
- /*
- * Count cycles. Watching the timer introduces a several microsecond
- * uncertaintity, so let it cook for a while and divide by the number of
- * ticks actually executed.
- */
+ uint8_t lsb, msb;
+ uint32_t max_timer_value;
+ uint32_t last_tick, cur_tick;
+ int32_t diff, remaining;
+
+ /* Set the timer to free running mode */
+ outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC);
+ /* Reset the 16 timer reload value, first LSB, then MSB */
+ outport_byte(TIMER_CNTR0, 0);
+ outport_byte(TIMER_CNTR0, 0);
+ /* We use the full 16 bit */
+ max_timer_value = 0xffff;
+ /* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */
+ remaining = TIMER_TICK;
begin_time = rdtsc();
-
- for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick;
- i != 0; --i ) {
- /* We know we've just completed a tick when timer goes from low to high */
- then_lsb = then_msb = 0xff;
- do {
- READ_8254(now_lsb, now_msb);
- if ((then_msb < now_msb) ||
- ((then_msb == now_msb) && (then_lsb < now_lsb)))
- break;
- then_lsb = now_lsb;
- then_msb = now_msb;
- } while (1);
+ READ_8254(lsb, msb);
+ last_tick = (msb << 8) | lsb;
+ while(remaining > 0) {
+ READ_8254(lsb, msb);
+ cur_tick = (msb << 8) | lsb;
+ /* PIT counts down, so subtract cur from last */
+ diff = last_tick - cur_tick;
+ last_tick = cur_tick;
+ if (diff < 0) {
+ diff += max_timer_value;
+ }
+ remaining -= diff;
}
pc586_tsc_frequency = rdtsc() - begin_time;
#if 0
- printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / 1000000));
+ printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency ));
#endif
}
static void clockOn(void)
{
+
+ /*
+ * First calibrate the TSC. Do this every time we
+ * turn the clock on in case the CPU clock speed has changed.
+ */
+ if ( x86_has_tsc() ) {
+ calibrate_tsc();
+ }
+
rtems_interrupt_lock_context lock_context;
pc386_isrs_per_tick = 1;
pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
@@ -171,13 +183,6 @@ static void clockOn(void)
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER );
-
- /*
- * Now calibrate cycles per tick. Do this every time we
- * turn the clock on in case the CPU clock speed has changed.
- */
- if ( x86_has_tsc() )
- calibrate_tsc();
}
bool Clock_isr_enabled = false;
diff --git a/bsps/include/bsp/irq-default.h b/bsps/include/bsp/irq-default.h
index a94e045e0d..4d7beb189b 100644
--- a/bsps/include/bsp/irq-default.h
+++ b/bsps/include/bsp/irq-default.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
@@ -5,9 +7,7 @@
*/
/*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (C) 2019 embedded brains GmbH
+ * Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/bsps/include/bsp/irq-generic.h b/bsps/include/bsp/irq-generic.h
index 31835d07ba..4135aa518c 100644
--- a/bsps/include/bsp/irq-generic.h
+++ b/bsps/include/bsp/irq-generic.h
@@ -1,27 +1,43 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt support API.
+ * @brief This header file provides interfaces of the generic interrupt
+ * controller support.
*/
/*
- * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
- *
- * Copyright (c) 2008, 2017 embedded brains GmbH.
+ * Copyright (C) 2016 Chris Johns <chrisj@rtems.org>
*
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2008, 2017 embedded brains GmbH (http://www.embedded-brains.de)
*
- * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The API is based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
*/
#ifndef LIBBSP_SHARED_IRQ_GENERIC_H
diff --git a/bsps/include/bsp/irq-info.h b/bsps/include/bsp/irq-info.h
index ea6d629e76..25f05a9f69 100644
--- a/bsps/include/bsp/irq-info.h
+++ b/bsps/include/bsp/irq-info.h
@@ -1,22 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt information API.
+ * @brief This header file provides interfaces of the generic interrupt
+ * controller support for the RTEMS Shell.
*/
/*
- * Copyright (c) 2008, 2009
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_SHARED_IRQ_INFO_H
diff --git a/bsps/include/grlib/ahbstat.h b/bsps/include/grlib/ahbstat.h
index 71e2330f69..0baaad0732 100644
--- a/bsps/include/grlib/ahbstat.h
+++ b/bsps/include/grlib/ahbstat.h
@@ -21,6 +21,8 @@ extern "C" {
struct ahbstat_regs {
volatile uint32_t status;
volatile uint32_t failing;
+ volatile uint32_t status2;
+ volatile uint32_t failing2;
};
/* AHB fail interrupt callback to user. This function is declared weak so that
diff --git a/bsps/include/grlib/ambapp_ids.h b/bsps/include/grlib/ambapp_ids.h
index c0c3547e94..629b4fb37a 100644
--- a/bsps/include/grlib/ambapp_ids.h
+++ b/bsps/include/grlib/ambapp_ids.h
@@ -226,6 +226,25 @@
#define GAISLER_SPIMASTER 0x0a6
#define GAISLER_SPISLAVE 0x0a7
#define GAISLER_GRSRIO 0x0a8
+#define GAISLER_AHBLM2AHB 0x0a9
+#define GAISLER_AHBS2NOC 0x0aa
+#define GAISLER_TCAU 0x0ab
+#define GAISLER_GRTMDYNVCID 0x0ac
+#define GAISLER_RNOCIRQPROP 0x0ad
+#define GAISLER_FTADDR 0x0ae
+#define GAISLER_ATG 0x0b0
+#define GAISLER_DFITRACE 0x0b1
+#define GAISLER_SELFTEST 0x0b2
+#define GAISLER_DFIERRINJ 0x0b3
+#define GAISLER_DFICHECK 0x0b4
+#define GAISLER_GRCANFD 0x0b5
+#define GAISLER_NIM 0x0b6
+#define GAISLER_BANDGAP 0x1f0
+#define GAISLER_MPROT 0x1f1
+#define GAISLER_ADC 0x1f2
+#define GAISLER_BO 0x1f3
+#define GAISLER_DAC 0x1f4
+#define GAISLER_PLL 0x1f6
#define GAISLER_PIPEWRAPPER 0xffa
#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */
diff --git a/bsps/include/grlib/canbtrs.h b/bsps/include/grlib/canbtrs.h
new file mode 100644
index 0000000000..7369136931
--- /dev/null
+++ b/bsps/include/grlib/canbtrs.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ * @ingroup can
+ * @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
+ */
+
+/*
+ * Copyright (C) 2019, 2020 Cobham Gaisler AB
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GRLIB_CANBTRS_H__
+#define __GRLIB_CANBTRS_H__
+
+/**
+ * @defgroup can CAN
+ *
+ * @ingroup RTEMSBSPsSharedGRLIB
+ *
+ * @brief CAN routines shared between OCCAN, GRCAN and GRCANFD controllers
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CAN Baud-rate parameters, range of valid parameter values */
+struct grlib_canbtrs_ranges {
+ unsigned int max_scaler;
+ char has_bpr;
+ unsigned char divfactor;
+ unsigned char min_tseg1;
+ unsigned char max_tseg1;
+ unsigned char min_tseg2;
+ unsigned char max_tseg2;
+};
+
+struct grlib_canbtrs_timing {
+ unsigned char scaler;
+ unsigned char ps1;
+ unsigned char ps2;
+ unsigned char rsj;
+ unsigned char bpr;
+};
+
+/* @brief Calculate CAN baud-rate generation parameters from requested baud-rate
+ *
+ * @param baud The CAN baud rate requested
+ * @param core_hz Input clock [Hz] to CAN core
+ * @param sampl_pt CAN sample point in %, 80 means 80%
+ * @param br CAN Baud-rate parameters limitations
+ * @param[out] timing result is placed here
+ *
+ * @retval 0 Baud-rate parameters sucessfully calculated
+ * @retval negative Failure to generate parameters with less than 5% error
+ * margin from requested baud-rate
+ */
+int grlib_canbtrs_calc_timing(
+ unsigned int baud,
+ unsigned int core_hz,
+ unsigned int sampl_pt,
+ struct grlib_canbtrs_ranges *br,
+ struct grlib_canbtrs_timing *timing
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsps/include/grlib/grcan.h b/bsps/include/grlib/grcan.h
index b1bc2ba758..a956bef124 100644
--- a/bsps/include/grlib/grcan.h
+++ b/bsps/include/grlib/grcan.h
@@ -1,6 +1,7 @@
/**
* @file
* @ingroup can
+ * @brief Driver API for the GRLIB GRCAN and GRCANFD controllers
*/
/*
@@ -25,6 +26,8 @@
* @{
*/
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -37,7 +40,13 @@ struct grcan_regs {
volatile unsigned int smask; /* 0x18 */
volatile unsigned int scode; /* 0x1C */
- volatile unsigned int dummy1[56]; /* 0x20-0xFC */
+ volatile unsigned int dummy1[8]; /* 0x20-0x3C */
+
+ volatile unsigned int nbtr; /* 0x40 */
+ volatile unsigned int fdbtr; /* 0x44 */
+ volatile unsigned int tdelay; /* 0x48 */
+
+ volatile unsigned int dummy1b[45]; /* 0x4C-0xFC */
volatile unsigned int pimsr; /* 0x100 */
volatile unsigned int pimr; /* 0x104 */
@@ -82,10 +91,18 @@ struct grcan_timing {
unsigned char scaler;
unsigned char ps1;
unsigned char ps2;
- unsigned int rsj;
+ unsigned char rsj;
unsigned char bpr;
};
+struct grcanfd_timing {
+ unsigned char scaler;
+ unsigned char ps1;
+ unsigned char ps2;
+ unsigned char sjw;
+ unsigned char resv_zero;
+};
+
struct grcan_selection {
int selection;
int enable0;
@@ -97,16 +114,34 @@ struct grcan_filter {
unsigned long long code;
};
+#define GRCAN_FDOPT_NOM 0
+#define GRCAN_FDOPT_FDBTR 0x01
+#define GRCAN_FDOPT_FDFRM 0x02
+#define GRCAN_FDMASK (GRCAN_FDOPT_FDBTR | GRCAN_FDOPT_FDFRM)
+
/* CAN MESSAGE */
typedef struct {
char extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
char rtr; /* RTR - Remote Transmission Request */
- char unused; /* unused */
+ char unused; /* Must be 0 to select classic CAN frame */
unsigned char len;
unsigned char data[8];
unsigned int id;
} CANMsg;
+/* CAN-FD MESSAGE */
+typedef struct {
+ uint8_t extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
+ uint8_t rtr; /* RTR - Remote Transmission Request */
+ uint8_t fdopts; /* Bit1: 1=Switch bit rate. bit2: 1=FD frame. */
+ uint8_t len; /* 0-8, 12, 16, 20, 24, 32, 48 or 64 bytes */
+ uint32_t id;
+ union {
+ uint64_t dwords[8]; /* up to 64 bytes if FD=1 and len>8 */
+ uint8_t bytes[64]; /* up to 64 bytes if FD=1 and len>8 */
+ } data;
+} CANFDMsg;
+
enum {
GRCAN_RET_OK = 0,
GRCAN_RET_INVARG = -1,
@@ -166,6 +201,26 @@ enum grcan_state {
#define GRCAN_RXCTRL_ENABLE 1
#define GRCAN_RXCTRL_ONGOING 1
+#define GRCANFD_NBTR_SCALER 0x00ff0000
+#define GRCANFD_NBTR_PS1 0x0000fc00
+#define GRCANFD_NBTR_PS2 0x000003e0
+#define GRCANFD_NBTR_SJW 0x0000001f
+
+#define GRCANFD_NBTR_SCALER_BIT 16
+#define GRCANFD_NBTR_PS1_BIT 10
+#define GRCANFD_NBTR_PS2_BIT 5
+#define GRCANFD_NBTR_SJW_BIT 0
+
+#define GRCANFD_FDBTR_SCALER 0x00ff0000
+#define GRCANFD_FDBTR_PS1 0x00003c00
+#define GRCANFD_FDBTR_PS2 0x000001e0
+#define GRCANFD_FDBTR_SJW 0x0000000f
+
+#define GRCANFD_FDBTR_SCALER_BIT 16
+#define GRCANFD_FDBTR_PS1_BIT 10
+#define GRCANFD_FDBTR_PS2_BIT 5
+#define GRCANFD_FDBTR_SJW_BIT 0
+
/* Relative offset of IRQ sources to AMBA Plug&Play */
#define GRCAN_IRQ_IRQ 0
#define GRCAN_IRQ_TXSYNC 1
@@ -230,6 +285,15 @@ extern void *grcan_open_by_name(char *name, int *dev_no);
extern int grcan_close(void *d);
/*
+ * Returns if CAN hardware device is CANFD capable.
+ *
+ * dev_no: Device handle
+ * return: 0=Not FD capable, 1=FD capable.
+ * function returns NULL if device can not be opened.
+ */
+extern int grcan_canfd_capable(void *d);
+
+/*
* Receive CAN messages
*
* Multiple CAN messages can be received in one call.
@@ -255,6 +319,31 @@ extern int grcan_read(
);
/*
+ * Receive CAN messages (only GRCANFD)
+ *
+ * Multiple CAN messages can be received in one call.
+ *
+ * d: Device handle
+ * msg: Pointer to receive messages
+ * count: Number of CAN messages to receive
+ *
+ * return:
+ * >=0: Number of CAN messages received. This can be
+ * less than the count parameter.
+ * GRCAN_RET_INVARG: count parameter less than one or NULL msg.
+ * GRCAN_RET_NOTSTARTED: Device not in started mode
+ * GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
+ * GRCAN_RET_BUSOFF: A read was interrupted by a bus-off error.
+ * Device has left started mode.
+ * GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
+ */
+extern int grcanfd_read(
+ void *d,
+ CANFDMsg *msg,
+ size_t count
+);
+
+/*
* Transmit CAN messages
*
* Multiple CAN messages can be transmit in one call.
@@ -280,6 +369,31 @@ extern int grcan_write(
);
/*
+ * Transmit CAN-FD complient messages (only GRCANFD)
+ *
+ * Multiple CAN messages can be transmit in one call.
+ *
+ * d: Device handle
+ * msg: Pointer to messages to transmit
+ * count: Number of CAN messages to transmit
+ *
+ * return:
+ * >=0: Number of CAN messages transmitted. This can be
+ * less than the count parameter.
+ * GRCAN_RET_INVARG: count parameter less than one.
+ * GRCAN_RET_NOTSTARTED: Device not in started mode
+ * GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
+ * GRCAN_RET_BUSOFF: A write was interrupted by a Bus-off error.
+ * Device has left started mode
+ * GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
+ */
+extern int grcanfd_write(
+ void *d,
+ CANFDMsg *msg,
+ size_t ucount
+);
+
+/*
* Returns current GRCAN software state
*
* If STATE_BUSOFF or STATE_AHBERR is returned then the function grcan_stop()
@@ -320,6 +434,16 @@ extern int grcan_set_speed(void *d, unsigned int hz);
/* Set baudrate by specifying the timing registers manually */
extern int grcan_set_btrs(void *d, const struct grcan_timing *timing);
+/* Set the Nominal and FD baudrate by using driver's baud rate timing
+ * calculation routines
+ */
+extern int grcanfd_set_speed(void *d, unsigned int nomhz, unsigned int fdhz);
+/* Set Nominal and FD baudrate by specifying the timing registers manually*/
+extern int grcanfd_set_btrs(
+ void *d,
+ const struct grcanfd_timing *nominal,
+ const struct grcanfd_timing *fd);
+
/* Functions can be called whenever */
/* Enable/disable Blocking on reception (until at least one message has been received) */
int grcan_set_rxblock(void* d, int block);
diff --git a/bsps/include/grlib/greth.h b/bsps/include/grlib/greth.h
index 1c42c99ddc..e7970a79f7 100644
--- a/bsps/include/grlib/greth.h
+++ b/bsps/include/grlib/greth.h
@@ -100,6 +100,7 @@ typedef struct _greth_regs {
#define GRETH_STATUS_TXIRQ 0x00000008 /* Transmit Error IRQ */
#define GRETH_STATUS_RXAHBERR 0x00000010 /* Receiver AHB Error */
#define GRETH_STATUS_TXAHBERR 0x00000020 /* Transmitter AHB Error */
+#define GRETH_STATUS_NRD 0x0f000000 /* Number of descriptors */
/* MDIO Control */
#define GRETH_MDIO_WRITE 0x00000001 /* MDIO Write */
diff --git a/bsps/include/grlib/grlib_impl.h b/bsps/include/grlib/grlib_impl.h
index e795e7f844..3bff2af0da 100644
--- a/bsps/include/grlib/grlib_impl.h
+++ b/bsps/include/grlib/grlib_impl.h
@@ -122,6 +122,16 @@ RTEMS_INLINE_ROUTINE unsigned int grlib_read_uncached32(unsigned int address)
return tmp;
}
+RTEMS_INLINE_ROUTINE uint64_t grlib_read_uncached64(uint64_t *address)
+{
+ uint64_t tmp;
+ __asm__ (" ldda [%1]1, %0 "
+ : "=r"(tmp)
+ : "r"(address)
+ );
+ return tmp;
+}
+
#define GRLIB_DMA_IS_CACHE_COHERENT CPU_SPARC_HAS_SNOOPING
#else
diff --git a/bsps/include/grlib/grspw_pkt.h b/bsps/include/grlib/grspw_pkt.h
index 595625b838..ede60b72a8 100644
--- a/bsps/include/grlib/grspw_pkt.h
+++ b/bsps/include/grlib/grspw_pkt.h
@@ -150,8 +150,8 @@ typedef enum {
SPW_LS_ERRRST = 0,
SPW_LS_ERRWAIT = 1,
SPW_LS_READY = 2,
- SPW_LS_CONNECTING = 3,
- SPW_LS_STARTED = 4,
+ SPW_LS_STARTED = 3,
+ SPW_LS_CONNECTING = 4,
SPW_LS_RUN = 5
} spw_link_state_t;
diff --git a/bsps/include/grlib/grspw_router.h b/bsps/include/grlib/grspw_router.h
index 2fab8d5f6c..8547f19de3 100644
--- a/bsps/include/grlib/grspw_router.h
+++ b/bsps/include/grlib/grspw_router.h
@@ -343,6 +343,7 @@ extern int router_port_enable(void *d, int port);
extern int router_port_disable(void *d, int port);
extern int router_port_link_stop(void *d, int port);
extern int router_port_link_start(void *d, int port);
+extern int router_port_link_div(void *d, int port, int rundiv);
extern int router_port_link_receive_spill(void *d, int port);
extern int router_port_link_transmit_reset(void *d, int port);
diff --git a/bsps/include/grlib/occan.h b/bsps/include/grlib/occan.h
index 0bf34dee48..1112a3e8dc 100644
--- a/bsps/include/grlib/occan.h
+++ b/bsps/include/grlib/occan.h
@@ -1,7 +1,7 @@
/**
* @file
* @ingroup can
- * @brief Gaisler wrapper to OpenCores CAN - driver interface
+ * @brief Driver API for GRLIB wrapper to OpenCores CAN
*/
/*
diff --git a/bsps/m68k/uC5282/start/linkcmds b/bsps/m68k/uC5282/start/linkcmds
index da97472f1b..af9a69b802 100644
--- a/bsps/m68k/uC5282/start/linkcmds
+++ b/bsps/m68k/uC5282/start/linkcmds
@@ -91,13 +91,13 @@ SECTIONS
* crtn.o are in.
*/
PROVIDE (_init = .);
- *crti.o(.init)
- *(.init)
- *crtn.o(.init)
+ KEEP (*crti.o(.init))
+ KEEP (*(.init))
+ KEEP (*crtn.o(.init))
PROVIDE (_fini = .);
- *crti.o(.fini)
- *(.fini)
- *crtn.o(.fini)
+ KEEP (*crti.o(.fini))
+ KEEP (*(.fini))
+ KEEP (*crtn.o(.fini))
/*
* Special FreeBSD sysctl sections.
@@ -122,18 +122,22 @@ SECTIONS
* crtend.o. The same comments apply to it.
*/
. = ALIGN (16);
- *crtbegin.o(.ctors)
- *(.ctors)
- *crtend.o(.ctors)
- *crtbegin.o(.dtors)
- *(.dtors)
- *crtend.o(.dtors)
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
/*
* Exception frame info
*/
. = ALIGN (16);
- *(.eh_frame)
+ KEEP (*(.eh_frame))
/*
* Read-only data
@@ -141,7 +145,7 @@ SECTIONS
. = ALIGN (16);
_rodata_start = . ;
*(.rodata*)
- KEEP (*(SORT(.rtemsroset.*)))
+ KEEP (*(SORT(.rtemsroset.*)))
*(.gnu.linkonce.r*)
. = ALIGN (16);
@@ -179,7 +183,7 @@ SECTIONS
KEEP (*(SORT(.rtemsrwset.*)))
*(.gnu.linkonce.d*)
*(.gcc_except_table*)
- *(.jcr)
+ KEEP (*(.jcr))
. = ALIGN (16);
PROVIDE (_edata = .);
PROVIDE (_copy_end = .);
diff --git a/bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c b/bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c
deleted file mode 100644
index 721ade30d1..0000000000
--- a/bsps/powerpc/beatnik/net/if_mve/mve_smallbuf_tst.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <rtems.h>
-#include <bsp.h>
-#include <bsp/if_mve_pub.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-/* Demo for the mv64360 ethernet quirk:
- *
- * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- * $$ buffer segments < 8 bytes must be aligned $$
- * $$ to 8 bytes but larger segments are not $$
- * $$ sensitive to alignment. $$
- * $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- *
- * How to use:
- *
- * Init MVE driver on (unused) unit 2:
- *
- * mve = mvtst_init(2)
- *
- * data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
- *
- * Alloc 2-element mbuf chain (1st holds an
- * ethernet header which is > 8bytes so we can't
- * test this with only 1 mbuf. The 2nd mbuf holds
- * a small fragment of data).
- *
- * mb = mvtst_getbuf(mve)
- *
- * Copy data into aligned area inside 2nd mbuf,
- * (so that you can see if the chip starts using
- * the aligned area rather than the unaligned
- * buffer pointer). Point mbuf's data pointer
- * at 'off'set from the aligned area:
- *
- * mvtst_putbuf(mb, data, len, offset)
- *
- * Send chain off:
- *
- * BSP_mve_send_buf(mve, mb, 0, 0)
- *
- * Watch raw data:
- *
- * tcpdump -XX -vv -s0 ether host <my-ether-addr>
- *
- * E.g, if offset = 1, len = 2 then we would like
- * to see
- *
- * GOOD:
- * < 14 header bytes > 0x02, 0x03
-
- * but if the chip starts DMA at aligned address
- * we see instead
- * BAD:
- * < 14 header bytes > 0x01, 0x02
- */
-
-static inline void *rmalloc(size_t l) { return malloc(l); }
-static inline void rfree(void *p) { return free(p); }
-
-#define _KERNEL
-#include <sys/param.h>
-#include <sys/mbuf.h>
-
-static void
-cleanup_buf(void *u_b, void *closure, int error)
-{
-rtems_bsdnet_semaphore_obtain();
- m_freem((struct mbuf*)u_b);
-rtems_bsdnet_semaphore_release();
-}
-
-struct mbuf *mvtst_getbuf(struct mveth_private *mp)
-{
-struct mbuf *m,*n;
-
- if ( !mp ) {
- printf("need driver ptr arg\n");
- return 0;
- }
-rtems_bsdnet_semaphore_obtain();
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- MGET(n, M_DONTWAIT, MT_DATA);
- m->m_next = n;
-rtems_bsdnet_semaphore_release();
- /* Ethernet header */
- memset( mtod(m, unsigned char*), 0xff, 6);
- BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
- /* Arbitrary; setting to IP but we don't bother
- * to setup a real IP header. We just watch the
- * raw packet contents...
- */
- mtod(m, unsigned char*)[12] = 0x08;
- mtod(m, unsigned char*)[13] = 0x00;
- m->m_pkthdr.len = m->m_len = 14;
- n->m_len = 0;
- return m;
-}
-
-int
-mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
-{
-int i;
- if ( m ) {
- m->m_pkthdr.len += len;
- if ( ( m= m->m_next ) ) {
- m->m_len = len;
- memcpy(mtod(m, void*), data, 32);
- m->m_data += off;
- printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
- for ( i=0; i< 16; i++ ) {
- printf(" %02x,",mtod(m, unsigned char*)[i]);
- }
- printf("\n");
- }
- }
-
- return 0;
-}
-
-static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
-{
- return *(void**)paddr = rmalloc((*p_size = 1800));
-}
-
-static void consume_buf(void *buf, void *closure, int len)
-{
- rfree(buf);
-}
-
-void *
-mvtst_init(int unit)
-{
-struct mveth_private *mp;
- mp = BSP_mve_setup(
- unit, 0,
- cleanup_buf, 0,
- alloc_rxbuf,
- consume_buf, 0,
- 10, 10,
- 0);
- if ( mp )
- BSP_mve_init_hw(mp, 0, 0);
- return mp;
-}
diff --git a/bsps/powerpc/beatnik/net/if_mve/testing.c b/bsps/powerpc/beatnik/net/if_mve/testing.c
deleted file mode 100644
index a1233bdb0b..0000000000
--- a/bsps/powerpc/beatnik/net/if_mve/testing.c
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef KERNEL
-#define KERNEL
-#endif
-
-#include <rtems.h>
-#include <rtems/rtems_bsdnet_internal.h>
-#include <bsp.h>
-#include <sys/param.h>
-#include <sys/mbuf.h>
-
-#include "mv64340_eth_ll.h"
-
-#include <string.h>
-#include <assert.h>
-
-#include <netinet/in.h>
-#include <stdio.h>
-
-#define RX_SPACING 1
-#define TX_SPACING 1
-
-#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
-#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
-
-
-struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
-struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
-
-struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
-struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
-
-/* packet buffers */
-char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
-char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
-
-char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
-char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
-
-char BcHeader[22] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
- 0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
- 00, 00, /* len */
- 0xAA, /* dsap */
- 0xAA, /* ssap */
- 0x03, /* ctrl */
- 0x08, 0x00, 0x56, /* snap_org [stanford] */
- 0x80, 0x5b, /* snap_type (stanford kernel) */
-};
-
-struct mv64340_private mveth = {
- port_num: 0,
- port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
- /* port_config .. tx_resource_err are set by port_init */
- 0
-};
-
-struct pkt_info p0,p1;
-
-static inline void rx_stopq(int port)
-{
- MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
-}
-
-static inline void tx_stopq(int port)
-{
- MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
-}
-
-#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
-#define MV64360_ENET2MEM_SNOOP_WT 0x1000
-#define MV64360_ENET2MEM_SNOOP_WB 0x2000
-
-#if 0
-int
-mveth_init(struct mv64340_private *mp)
-{
-int i;
- mp->p_rx_desc_area = rx_ring;
- mp->p_tx_desc_area = tx_ring;
-
- rx_stopq(mp->port_num);
- tx_stopq(mp->port_num);
-
- /* MotLoad has cache snooping disabled on the ENET2MEM windows.
- * Some comments in (linux) indicate that there are errata
- * which cause problems which is a real bummer.
- * We try it anyways...
- */
- {
- unsigned long disbl, bar;
- disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
- /* disable all 6 windows */
- MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
- /* set WB snooping */
- for ( i=0; i<6*8; i+=8 ) {
- if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
- MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
- /* read back to flush fifo [linux comment] */
- (void)MV_READ(MV64340_ETH_BAR_0 + i);
- }
- }
- /* restore/re-enable */
- MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
- }
-
- eth_port_init(mp);
-
- sleep(1);
-
- mveth_init_tx_desc_ring(mp);
- mveth_init_rx_desc_ring(mp);
-#if 0
- for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
- p0.byte_cnt = sizeof(rx_buf[0]);
- p0.buf_ptr = (dma_addr_t)rx_buf[i];
- p0.return_info = (void*)i;
- /* other fields are not used by ll driver */
- assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
- }
- memset(&p0, 0, sizeof(p0));
-#endif
-
- return eth_port_start(mp);
-}
-#endif
-
-void
-mveth_stop(struct mv64340_private *mp)
-{
-extern void mveth_stop_hw();
- rtems_bsdnet_semaphore_obtain();
- mveth_stop_hw(mp);
- rtems_bsdnet_semaphore_release();
-}
-
-extern int mveth_send_mbuf();
-extern int mveth_swipe_tx();
-
-int
-mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
-{
-int rval = -1,l;
-char *p;
-struct mbuf *m;
-char *emsg = 0;
-
- rtems_bsdnet_semaphore_obtain();
- MGETHDR(m, M_WAIT, MT_DATA);
- if ( !m ) {
- emsg="Unable to allocate header\n";
- goto bail;
- }
- MCLGET(m, M_WAIT);
- if ( !(m->m_flags & M_EXT) ) {
- m_freem(m);
- emsg="Unable to allocate cluster\n";
- goto bail;
- }
- p = mtod(m, char *);
- l = 0;
- switch (nbufs) {
- case 3:
- default:
- emsg="nbufs arg must be 1..3\n";
- goto bail;
-
- case 1:
- l += sizeof(BcHeader);
- memcpy(p, &BcHeader, sizeof(BcHeader));
- p += sizeof(BcHeader);
-
- case 2:
- memcpy(p,data,len);
- l += len;
- m->m_len = m->m_pkthdr.len = l;
- if ( 2 == nbufs ) {
- M_PREPEND(m, sizeof (BcHeader), M_WAIT);
- if (!m) {
- emsg = "Unable to prepend\n";
- goto bail;
- }
- p = mtod(m, char*);
- memcpy(p,&BcHeader,sizeof(BcHeader));
- l += sizeof(BcHeader);
- }
- break;
- }
- *(short*)(mtod(m, char*) + 12) = htons(l-14);
- rval = mveth_send_mbuf(mp,m);
-
-bail:
- rtems_bsdnet_semaphore_release();
- if (emsg)
- printf(emsg);
-
-#if 0
- /*
- * Add local net header. If no space in first mbuf,
- * allocate another.
- */
- M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
- if (m == 0)
- senderr(ENOBUFS);
- eh = mtod(m, struct ether_header *);
- (void)memcpy(&eh->ether_type, &type,
- sizeof(eh->ether_type));
- (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
- (void)memcpy(eh->ether_shost, ac->ac_enaddr,
- sizeof(eh->ether_shost));
-#endif
- return rval;
-}
-
-int
-mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
-{
-int rval;
- rtems_bsdnet_semaphore_obtain();
- rval = p(mp);
- rtems_bsdnet_semaphore_release();
- return rval;
-}
-
-int
-mveth_rx(struct mv64340_private *mp)
-{
-extern int mveth_swipe_rx();
- return mveth_protected(mveth_swipe_rx,mp);
-}
-
-int
-mveth_reclaim(struct mv64340_private *mp)
-{
-extern int mveth_swipe_tx();
- return mveth_protected(mveth_swipe_tx,mp);
-}
-
-
-int preth(FILE *f, char *p)
-{
-int i;
- for (i=0; i<4; i++)
- fprintf(f,"%02X:",p[i]);
- fprintf(f,"%02X",p[i]);
- return 6;
-}
-
-char *errcode2str(st)
-{
-char *rval;
- switch(st) {
- case ETH_OK:
- rval = "OK";
- break;
- case ETH_ERROR:
- rval = "Fundamental error.";
- break;
- case ETH_RETRY:
- rval = "Could not process request. Try later.";
- break;
- case ETH_END_OF_JOB:
- rval = "Ring has nothing to process.";
- break;
- case ETH_QUEUE_FULL:
- rval = "Ring resource error.";
- break;
- case ETH_QUEUE_LAST_RESOURCE:
- rval = "Ring resources about to exhaust.";
- break;
- default:
- rval = "UNKNOWN"; break;
- }
- return rval;
-}
-
-
-#if 0
-int
-mveth_rx(struct mv64340_private *mp)
-{
-int st;
-struct pkt_info p;
- if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
- fprintf(stderr,"receive: %s\n", errcode2str(st));
- return -1;
- }
- printf("%i bytes received from ", p.byte_cnt);
- preth(stdout,(char*)p.buf_ptr+6);
- printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
-
- p.byte_cnt = sizeof(rx_buf[0]);
- p.buf_ptr -= RX_BUF_OFFSET;
- if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
- fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
- return -1;
- }
- return 0;
-}
-#endif
-
-int
-dring()
-{
-int i;
-if (1) {
-struct eth_rx_desc *pr;
-printf("RX:\n");
- for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
- dcbi(pr);
- printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
- pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
- }
-}
-if (1) {
-struct eth_tx_desc *pt;
-printf("TX:\n");
- for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
- dcbi(pt);
- printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
- pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
- }
-}
- return 0;
-}
diff --git a/bsps/powerpc/beatnik/net/porting/if_xxx.modini.c b/bsps/powerpc/beatnik/net/porting/if_xxx.modini.c
deleted file mode 100644
index 1abad7dc22..0000000000
--- a/bsps/powerpc/beatnik/net/porting/if_xxx.modini.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <rtems.h>
-#include <porting/rtemscompat.h>
-
-/* CEXP module initialization/finalization */
-
-/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
- * License: see LICENSE file.
- */
-
-void
-_cexpModuleInitialize(void *unused)
-{
-extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
- METHODSPTR = &METHODS;
-/*
-#ifdef DEBUG
- NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
-#endif
-*/
-}
-
-int
-_cexpModuleFinalize(void *unused)
-{
-#ifdef DEBUG
-extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
- if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
- return -1;
- METHODSPTR = 0;
- return 0;
-#else
- return -1;
-#endif
-}
diff --git a/bsps/powerpc/include/bsp/irq_supp.h b/bsps/powerpc/include/bsp/irq_supp.h
index 65af48c87f..fbb16d6211 100644
--- a/bsps/powerpc/include/bsp/irq_supp.h
+++ b/bsps/powerpc/include/bsp/irq_supp.h
@@ -50,6 +50,11 @@ extern int BSP_disable_irq_at_pic(const rtems_irq_number irqLine);
*/
extern int BSP_setup_the_pic(rtems_irq_global_settings* config);
+/*
+ * Set up for the irq-generic.h interface.
+ */
+int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config);
+
/* IRQ dispatcher to be defined by the PIC driver; note that it MUST
* implement shared interrupts.
* Note also that the exception frame passed to this handler is not very
diff --git a/bsps/powerpc/include/libcpu/io.h b/bsps/powerpc/include/libcpu/io.h
index 521c97801d..c4e529f4d5 100644
--- a/bsps/powerpc/include/libcpu/io.h
+++ b/bsps/powerpc/include/libcpu/io.h
@@ -107,6 +107,7 @@ static inline void out_be16(volatile uint16_t *addr, uint16_t val)
__asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
+#ifndef in_le32
static inline uint32_t in_le32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -115,7 +116,9 @@ static inline uint32_t in_le32(const volatile uint32_t *addr)
"r" (addr), "m" (*addr));
return ret;
}
+#endif
+#ifndef in_be32
static inline uint32_t in_be32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -123,17 +126,22 @@ static inline uint32_t in_be32(const volatile uint32_t *addr)
__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
return ret;
}
+#endif
+#ifndef out_le32
static inline void out_le32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
"r" (val), "r" (addr));
}
+#endif
+#ifndef out_be32
static inline void out_be32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
+#endif
#endif /* ASM */
#endif /* _LIBCPU_IO_H */
diff --git a/bsps/powerpc/motorola_powerpc/bootloader/misc.c b/bsps/powerpc/motorola_powerpc/bootloader/misc.c
index 587bcffcff..ff2e3ff590 100644
--- a/bsps/powerpc/motorola_powerpc/bootloader/misc.c
+++ b/bsps/powerpc/motorola_powerpc/bootloader/misc.c
@@ -23,6 +23,8 @@
#include <rtems/bspIo.h>
#include <bsp.h>
+#include <rtems.h>
+
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr) + PAGE_MASK) & ~PAGE_MASK)
@@ -401,7 +403,7 @@ setup_hw(void)
}
#endif
- printk("\nRTEMS 4.x/PPC load: ");
+ printk("\nRTEMS " RTEMS_VERSION "/PPC load: ");
timer = 0;
cp = bd->cmd_line+strlen(bd->cmd_line);
while (timer++ < 5*1000) {
diff --git a/bsps/powerpc/motorola_powerpc/bootloader/ppcboot.lds b/bsps/powerpc/motorola_powerpc/bootloader/ppcboot.lds
index 0ee7447546..501acc40dc 100644
--- a/bsps/powerpc/motorola_powerpc/bootloader/ppcboot.lds
+++ b/bsps/powerpc/motorola_powerpc/bootloader/ppcboot.lds
@@ -38,7 +38,9 @@ SECTIONS
BYTE(0x75); BYTE(0x78); /* Partition name */
. = 0x400;
*(.text)
+ *(.text*)
*(.sdata2)
+ *(.sdata2*)
*(.rodata)
*(.rodata*)
}
@@ -71,13 +73,17 @@ SECTIONS
*(.data)
*(.data*)
*(.sdata)
+ *(.sdata*)
. = ALIGN(4);
_data_end = .;
}
.bss :
{
*(.sbss)
+ *(.sbss*)
*(.bss)
+ *(.bss*)
+ *(COMMON)
. = ALIGN(4);
_bss_end = .;
}
@@ -95,7 +101,7 @@ SECTIONS
/DISCARD/ :
{
- *(.comment)
+ *(.comment*)
+ *(.debug*)
}
}
-
diff --git a/bsps/powerpc/motorola_powerpc/include/bsp.h b/bsps/powerpc/motorola_powerpc/include/bsp.h
index 62e740272a..7d362bf406 100644
--- a/bsps/powerpc/motorola_powerpc/include/bsp.h
+++ b/bsps/powerpc/motorola_powerpc/include/bsp.h
@@ -31,11 +31,11 @@
#include <rtems.h>
#include <libcpu/io.h>
#include <bsp/vectors.h>
-
+
#ifdef qemu
#include <rtems/bspcmdline.h>
#endif
-
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -115,6 +115,36 @@ extern "C" {
#endif
#endif
+/*
+ * The BSP has PCI devices. Enable support in LibBSD.
+ */
+#define BSP_HAS_PC_PCI
+
+/*
+ * Remap the PCI address space for LibBSD
+ */
+#define RTEMS_BSP_PCI_IO_REGION_BASE 0
+#define RTEMS_BSP_PCI_MEM_REGION_BASE PCI_DRAM_OFFSET
+
+/*
+ * Remap the PCI address space for LibBSD
+ */
+#define RTEMS_BSP_ADDR_PTR(_type) uint ## _type ## _t __volatile*
+#define RTEMS_BSP_ADDR_CPTR(_type) const RTEMS_BSP_ADDR_PTR(_type)
+#define RTEMS_BSP_ADDRESS_READ(_addr, _type) \
+ *((RTEMS_BSP_ADDR_CPTR(_type)) (((RTEMS_BSP_ADDR_CPTR(8)) _addr) + PCI_DRAM_OFFSET))
+#define RTEMS_BSP_ADDRESS_WRITE(_addr, _val, _type) \
+ *((RTEMS_BSP_ADDR_PTR(_type)) (((RTEMS_BSP_ADDR_PTR(8)) _addr) + PCI_DRAM_OFFSET)) = (_val)
+
+#define RTEMS_BSP_READ_1(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 8)
+#define RTEMS_BSP_READ_2(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 16)
+#define RTEMS_BSP_READ_4(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 32)
+#define RTEMS_BSP_READ_8(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 64)
+
+#define RTEMS_BSP_WRITE_1(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 8)
+#define RTEMS_BSP_WRITE_2(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 16)
+#define RTEMS_BSP_WRITE_4(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 32)
+#define RTEMS_BSP_WRITE_8(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 64)
/*
* Base address definitions for several devices
diff --git a/bsps/powerpc/motorola_powerpc/include/bsp/irq.h b/bsps/powerpc/motorola_powerpc/include/bsp/irq.h
index 3690dbbff7..cbb6ff69cf 100644
--- a/bsps/powerpc/motorola_powerpc/include/bsp/irq.h
+++ b/bsps/powerpc/motorola_powerpc/include/bsp/irq.h
@@ -19,9 +19,17 @@
#ifndef BSP_POWERPC_IRQ_H
#define BSP_POWERPC_IRQ_H
+#ifndef BSP_SHARED_HANDLER_SUPPORT
#define BSP_SHARED_HANDLER_SUPPORT 1
+#endif
+
#include <rtems/irq.h>
-#include <bsp/irq-default.h>
+
+/*
+ * Switch to using the generic support. Remove this when all BSPs have
+ * been converted.
+ */
+#define BSP_POWERPC_IRQ_GENERIC_SUPPORT 1
/*
* 8259 edge/level control definitions at VIA
@@ -107,6 +115,8 @@ extern "C" {
#define BSP_IRQ_NUMBER (BSP_MISC_IRQ_MAX_OFFSET + 1)
#define BSP_LOWEST_OFFSET (BSP_ISA_IRQ_LOWEST_OFFSET)
#define BSP_MAX_OFFSET (BSP_MISC_IRQ_MAX_OFFSET)
+#define BSP_INTERRUPT_VECTOR_MIN (BSP_LOWEST_OFFSET)
+#define BSP_INTERRUPT_VECTOR_MAX (BSP_MAX_OFFSET)
/*
* Some ISA IRQ symbolic name definition
*/
@@ -191,6 +201,9 @@ int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
*/
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine);
+unsigned short BSP_irq_suspend_i8259s(unsigned short mask);
+void BSP_irq_resume_i8259s(unsigned short in_progress_save);
+
extern void BSP_rtems_irq_mng_init(unsigned cpuId);
extern void BSP_i8259s_init(void);
diff --git a/bsps/powerpc/motorola_powerpc/start/bspstart.c b/bsps/powerpc/motorola_powerpc/start/bspstart.c
index e74b02c446..ef8418e2c6 100644
--- a/bsps/powerpc/motorola_powerpc/start/bspstart.c
+++ b/bsps/powerpc/motorola_powerpc/start/bspstart.c
@@ -27,6 +27,7 @@
#include <bsp/pci.h>
#include <bsp/openpic.h>
#include <bsp/irq.h>
+#include <bsp/irq-generic.h>
#include <libcpu/bat.h>
#include <libcpu/pte121.h>
#include <libcpu/cpuIdent.h>
@@ -334,10 +335,8 @@ static void bsp_early( void )
*/
bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000);
- /*
- * Initalize RTEMS IRQ system
- */
- BSP_rtems_irq_mng_init(0);
+ /* Initialize interrupt support */
+ bsp_interrupt_initialize();
/* Activate the page table mappings only after
* initializing interrupts because the irq_mng_init()
diff --git a/bsps/powerpc/shared/irq/i8259.c b/bsps/powerpc/shared/irq/i8259.c
index 7363e87ba0..6a80e24946 100644
--- a/bsps/powerpc/shared/irq/i8259.c
+++ b/bsps/powerpc/shared/irq/i8259.c
@@ -12,6 +12,19 @@
#include <bsp.h>
#include <bsp/irq.h>
+#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
+#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
+
+/* Operation control word type 3. Bit 3 (0x08) must be set. Even address. */
+#define PIC_OCW3_RIS 0x01 /* 1 = read IS, 0 = read IR */
+#define PIC_OCW3_RR 0x02 /* register read */
+#define PIC_OCW3_P 0x04 /* poll mode command */
+/* 0x08 must be 1 to select OCW3 vs OCW2 */
+#define PIC_OCW3_SEL 0x08 /* must be 1 */
+/* 0x10 must be 0 to select OCW3 vs ICW1 */
+#define PIC_OCW3_SMM 0x20 /* special mode mask */
+#define PIC_OCW3_ESMM 0x40 /* enable SMM */
+
/*-------------------------------------------------------------------------+
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
+--------------------------------------------------------------------------*/
@@ -19,91 +32,137 @@
* lower byte is interrupt mask on the master PIC.
* while upper bits are interrupt on the slave PIC.
*/
-volatile rtems_i8259_masks i8259s_cache = 0xfffb;
+static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
+static rtems_i8259_masks i8259s_in_progress = 0;
+
+static inline
+void BSP_i8259s_irq_update_master_imr( void )
+{
+ rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
+ outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
+}
+
+static inline
+void BSP_i8259s_irq_update_slave_imr( void )
+{
+ rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
+ outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
+}
+
+/*
+ * Is the IRQ valid?
+ */
+static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
+{
+ return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
+ ((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
+}
+
+/*
+ * Read the IRR register. The default.
+ */
+static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
+{
+ uint8_t isr;
+ inport_byte(ioport, isr);
+ return isr;
+}
+
+/*
+ * Read the ISR register. Keep the default of the IRR.
+ */
+static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
+{
+ uint8_t isr;
+ outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
+ inport_byte(ioport, isr);
+ outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
+ return isr;
+}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_disable_at_i8259s
| Description: Mask IRQ line in appropriate PIC chip.
-| Global Variables: i8259s_cache
+| Global Variables: i8259s_imr_cache, i8259s_in_progress
| Arguments: vector_offset - number of IRQ line to mask.
-| Returns: original state or -1 on error.
+| Returns: 0 is OK.
+--------------------------------------------------------------------------*/
-int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine)
+int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
{
unsigned short mask;
rtems_interrupt_level level;
- int rval;
- if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
- ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
- )
+ if (!BSP_i8259s_irq_valid(irqLine))
return -1;
rtems_interrupt_disable(level);
mask = 1 << irqLine;
- rval = i8259s_cache & mask ? 0 : 1;
- i8259s_cache |= mask;
+ i8259s_imr_cache |= mask;
if (irqLine < 8)
{
- outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
+ BSP_i8259s_irq_update_master_imr();
}
else
{
- outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
+ BSP_i8259s_irq_update_slave_imr();
}
+
rtems_interrupt_enable(level);
- return rval;
+ return 0;
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_enable_at_i8259s
| Description: Unmask IRQ line in appropriate PIC chip.
-| Global Variables: i8259s_cache
+| Global Variables: i8259s_imr_cache, i8259s_in_progress
| Arguments: irqLine - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
-int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine)
+int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
{
- unsigned short mask;
rtems_interrupt_level level;
+ unsigned short mask;
+ uint8_t isr;
+ uint8_t irr;
- if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
- ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
- )
+ if (!BSP_i8259s_irq_valid(irqLine))
return 1;
rtems_interrupt_disable(level);
- mask = ~(1 << irqLine);
- i8259s_cache &= mask;
+ mask = 1 << irqLine;
+ i8259s_imr_cache &= ~mask;
if (irqLine < 8)
{
- outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
+ isr = BSP_i8259s_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
+ irr = BSP_i8259s_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
+ BSP_i8259s_irq_update_master_imr();
}
else
{
- outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
+ isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
+ irr = BSP_i8259s_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
+ BSP_i8259s_irq_update_slave_imr();
}
+
rtems_interrupt_enable(level);
return 0;
} /* mask_irq */
-int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
+int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
{
unsigned short mask;
- if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
- ((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
- )
+ if (!BSP_i8259s_irq_valid(irqLine))
return 1;
mask = (1 << irqLine);
- return (~(i8259s_cache & mask));
+ return (~(i8259s_imr_cache & mask));
}
/*-------------------------------------------------------------------------+
@@ -113,24 +172,47 @@ int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
| Arguments: irqLine - number of IRQ line to acknowledge.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
-int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine)
+int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
{
+ uint8_t slave_isr = 0;
+
if (irqLine >= 8) {
- outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI);
- outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8)));
- }
- else {
- outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine));
+ outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
+ slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
}
+ /*
+ * Only issue the EOI to the master if there are no more interrupts in
+ * service for the slave. i8259a data sheet page 18, The Special Fully Nested
+ * Mode, b.
+ */
+ if (slave_isr == 0)
+ outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
+
return 0;
} /* ackIRQ */
+unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
+{
+ unsigned short in_progress_save = i8259s_in_progress;
+ i8259s_in_progress |= mask;
+ BSP_i8259s_irq_update_master_imr();
+ BSP_i8259s_irq_update_slave_imr();
+ return in_progress_save;
+}
+
+void BSP_irq_resume_i8259s(unsigned short in_progress_save)
+{
+ i8259s_in_progress = in_progress_save;
+ BSP_i8259s_irq_update_master_imr();
+ BSP_i8259s_irq_update_slave_imr();
+}
+
void BSP_i8259s_init(void)
{
/*
- * init master 8259 interrupt controller
+ * Always mask at least current interrupt to prevent re-entrance
*/
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
diff --git a/bsps/powerpc/shared/irq/irq_init.c b/bsps/powerpc/shared/irq/irq_init.c
index 1a44992a5b..233c659b85 100644
--- a/bsps/powerpc/shared/irq/irq_init.c
+++ b/bsps/powerpc/shared/irq/irq_init.c
@@ -280,6 +280,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
int known_cpi_isa_bridge = 0;
#endif
int i;
+ int r;
/*
* First initialize the Interrupt management hardware
@@ -310,7 +311,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
#endif
known_cpi_isa_bridge = 1;
}
- if ( currentBoard == MVME_2300 ) {
+ if ( currentBoard == MVME_2300 || currentBoard == MVME_2600_2700_W_MVME761 ) {
/* nothing to do for W83C553 bridge */
known_cpi_isa_bridge = 1;
}
@@ -351,7 +352,19 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
initial_config.irqBase = BSP_LOWEST_OFFSET;
initial_config.irqPrioTbl = irqPrioTable;
- if (!BSP_rtems_irq_mngt_set(&initial_config)) {
+#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
+#ifdef TRACE_IRQ_INIT
+ printk("RTEMS IRQ management: irq-generic\n");
+#endif
+ r = BSP_rtems_irq_generic_set(&initial_config);
+#else
+#ifdef TRACE_IRQ_INIT
+ printk("RTEMS IRQ management: legacy\n");
+#endif
+ r = BSP_rtems_irq_mngt_set(&initial_config);
+#endif
+
+ if (!r) {
/*
* put something here that will show the failure...
*/
diff --git a/bsps/powerpc/shared/irq/openpic_i8259_irq.c b/bsps/powerpc/shared/irq/openpic_i8259_irq.c
index 4a9c393f7f..2617555658 100644
--- a/bsps/powerpc/shared/irq/openpic_i8259_irq.c
+++ b/bsps/powerpc/shared/irq/openpic_i8259_irq.c
@@ -15,6 +15,7 @@
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/irq_supp.h>
+#include <bsp/irq-generic.h>
#ifndef BSP_HAS_NO_VME
#include <bsp/VMEConfig.h>
#endif
@@ -214,7 +215,7 @@ int BSP_setup_the_pic(rtems_irq_global_settings* config)
/*
* Must enable PCI/ISA bridge IRQ
*/
- openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ);
+ openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ - BSP_PCI_IRQ_LOWEST_OFFSET);
#endif
#endif
@@ -234,15 +235,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#if BSP_ISA_IRQ_NUMBER > 0
register unsigned isaIntr; /* boolean */
register unsigned oldMask = 0; /* old isa pic masks */
- register unsigned newMask; /* new isa pic masks */
#endif
if (excNum == ASM_DEC_VECTOR) {
-
- bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
-
+#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
+ bsp_interrupt_handler_dispatch(BSP_DECREMENTER);
+#else
+ bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
+#endif
return 0;
-
}
#if BSP_PCI_IRQ_NUMBER > 0
@@ -274,7 +275,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#if BSP_ISA_IRQ_NUMBER > 0
#ifdef BSP_PCI_ISA_BRIDGE_IRQ
-#if 0 == BSP_PCI_IRQ_NUMBER
+#if 0 == BSP_PCI_IRQ_NUMBER
#error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ"
#endif
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
@@ -289,11 +290,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
/*
* store current PIC mask
*/
- oldMask = i8259s_cache;
- newMask = oldMask | irq_mask_or_tbl [irq];
- i8259s_cache = newMask;
- outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
- outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
+ oldMask = BSP_irq_suspend_i8259s(irq_mask_or_tbl [irq]);
BSP_irq_ack_at_i8259s (irq);
#if BSP_PCI_IRQ_NUMBER > 0
if ( OpenPIC )
@@ -303,13 +300,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#endif
/* dispatch handlers */
+#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
+ bsp_interrupt_handler_dispatch(irq);
+#else
bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl);
+#endif
#if BSP_ISA_IRQ_NUMBER > 0
if (isaIntr) {
- i8259s_cache = oldMask;
- outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
- outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
+ BSP_irq_resume_i8259s(oldMask);
}
else
#endif
diff --git a/bsps/powerpc/shared/irq/ppc-irq-generic.c b/bsps/powerpc/shared/irq/ppc-irq-generic.c
new file mode 100644
index 0000000000..8a70109e52
--- /dev/null
+++ b/bsps/powerpc/shared/irq/ppc-irq-generic.c
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSBSPsPowerPC
+ *
+ * @brief Generic Interrupt suppoer
+ */
+
+/*
+ * Copyright (C) 2021 Chris Johns. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <rtems/bspIo.h> /* for printk */
+#include <libcpu/spr.h>
+#include <bsp/irq_supp.h>
+#include <bsp/irq-generic.h>
+#include <bsp/vectors.h>
+
+SPR_RW(BOOKE_TSR)
+SPR_RW(PPC405_TSR)
+
+/* legacy mode for bookE DEC exception;
+ * to avoid the double layer of function calls
+ * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
+ * it is preferrable for the user to hook the DEC
+ * exception directly.
+ * However, the legacy mode works with less modifications
+ * of user code.
+ */
+static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
+{
+ /* clear interrupt; we must do this
+ * before C_dispatch_irq_handler()
+ * re-enables MSR_EE.
+ * Note that PPC405 uses a different SPR# for TSR
+ */
+ if (ppc_cpu_is_bookE()==PPC_BOOKE_405)
+ _write_PPC405_TSR( BOOKE_TSR_DIS );
+ else
+ _write_BOOKE_TSR( BOOKE_TSR_DIS );
+ return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);
+}
+
+/*
+ * RTEMS Global Interrupt Handler Management Routines
+ */
+int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config)
+{
+ int r;
+
+ r = BSP_setup_the_pic(config);
+ if (!r)
+ return r;
+
+ ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);
+ if ( ppc_cpu_is_bookE() ) {
+ /* bookE decrementer interrupt needs to be cleared BEFORE
+ * dispatching the user ISR (because the user ISR is called
+ * with EE enabled)
+ * We do this so that existing DEC handlers can be used
+ * with minor modifications.
+ */
+ ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
+ } else {
+ ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
+ }
+
+ return 1;
+}
+
+void bsp_interrupt_vector_enable(rtems_vector_number vector)
+{
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+ BSP_enable_irq_at_pic(vector);
+}
+
+void bsp_interrupt_vector_disable(rtems_vector_number vector)
+{
+ bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
+ BSP_disable_irq_at_pic(vector);
+}
+
+rtems_status_code bsp_interrupt_facility_initialize(void)
+{
+ /*
+ * Initialize RTEMS IRQ system
+ */
+ BSP_rtems_irq_mng_init(0);
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/shared/grlib-sources.am b/bsps/shared/grlib-sources.am
index 512a48c7f7..3dd3bdd89e 100644
--- a/bsps/shared/grlib-sources.am
+++ b/bsps/shared/grlib-sources.am
@@ -20,8 +20,11 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/ascs/grascs.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/gptimer.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib_ckinit.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canbtrs.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canmux.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcan.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanfd.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanstd.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/occan.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/satcan.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/drvmgr/ambapp_bus.c
diff --git a/bsps/shared/grlib/1553/gr1553b.c b/bsps/shared/grlib/1553/gr1553b.c
index 777b6dc743..179f5e3786 100644
--- a/bsps/shared/grlib/1553/gr1553b.c
+++ b/bsps/shared/grlib/1553/gr1553b.c
@@ -206,6 +206,10 @@ static int gr1553_init2(struct drvmgr_dev *dev)
GR1553B_WRITE_REG(&regs->rt_cfg, 0x15530000);
/* Stop BM logging (just in case) */
GR1553B_WRITE_REG(&regs->bm_ctrl, 0);
+ /* Set codec version. This is only supported by some devices, i.e. GR740.
+ * It will not have any effect on devices that does not support this bit.
+ */
+ GR1553B_WRITE_REG(&regs->hwcfg, 1<<12);
return DRVMGR_OK;
}
diff --git a/bsps/shared/grlib/1553/gr1553bc.c b/bsps/shared/grlib/1553/gr1553bc.c
index a22e2d8007..f37364e0ea 100644
--- a/bsps/shared/grlib/1553/gr1553bc.c
+++ b/bsps/shared/grlib/1553/gr1553bc.c
@@ -63,7 +63,7 @@ struct gr1553bc_priv {
*/
#define NEXT_MINOR_MARKER 0x01
-/* To separate ASYNC list from SYNC list we mark them differently, but with
+/* To separate ASYNC list from SYNC list we mark them differently, but with
* LSB always set. This can be used to get the list the descriptor is a part
* of.
*/
@@ -71,7 +71,7 @@ struct gr1553bc_priv {
struct gr1553bc_list_cfg gr1553bc_def_cfg =
{
- .rt_timeout =
+ .rt_timeout =
{
20, 20, 20, 20,
20, 20, 20, 20,
@@ -80,7 +80,7 @@ struct gr1553bc_list_cfg gr1553bc_def_cfg =
20, 20, 20, 20,
20, 20, 20, 20,
20, 20, 20, 20,
- 20, 20, 20
+ 20, 20, 20
},
.bc_timeout = 30,
.tropt_irq_on_err = 0,
@@ -132,7 +132,7 @@ int gr1553bc_list_config
/* RT Time Tolerances */
for (i=0; i<31; i++) {
- /* 0=14us, 1=18us ... 0xf=74us
+ /* 0=14us, 1=18us ... 0xf=74us
* round upwards: 15us will be 18us
*/
timeout = ((cfg->rt_timeout[i] + 1) - 14) / 4;
@@ -167,7 +167,7 @@ void gr1553bc_list_link_major(
if ( major ) {
major->next = next;
if ( next ) {
- major->minors[major->cfg->minor_cnt-1]->next =
+ major->minors[major->cfg->minor_cnt-1]->next =
next->minors[0];
} else {
major->minors[major->cfg->minor_cnt-1]->next = NULL;
@@ -195,7 +195,7 @@ int gr1553bc_list_set_major(
prev = list->majors[list->major_cnt-1];
}
- /* Link to next Major if not the last one and if there is
+ /* Link to next Major if not the last one and if there is
* a next major
*/
if ( no == list->major_cnt-1 ) {
@@ -262,7 +262,7 @@ int gr1553bc_list_table_size(struct gr1553bc_list *list)
minor_cnt = major->cfg->minor_cnt;
for (j=0; j<minor_cnt; j++) {
/* 128-bit Alignment required by HW */
- size += (GR1553BC_BD_ALIGN -
+ size += (GR1553BC_BD_ALIGN -
(size & (GR1553BC_BD_ALIGN-1))) &
~(GR1553BC_BD_ALIGN-1);
@@ -284,6 +284,7 @@ int gr1553bc_list_table_alloc
int i, j, minor_cnt, size;
unsigned int table;
struct gr1553bc_priv *bcpriv = list->bc;
+ int retval = 0;
/* Free previous allocated descriptor table */
gr1553bc_list_table_free(list);
@@ -298,8 +299,8 @@ int gr1553bc_list_table_alloc
/* Address given in Hardware accessible address, we
* convert it into CPU-accessible address.
*/
- list->table_hw = (unsigned int)bdtab_custom & ~0x1;
- list->_table = bdtab_custom;
+ list->_table = (void*)((unsigned int)bdtab_custom & ~0x1);
+ list->table_hw = (unsigned int)list->_table;
drvmgr_translate_check(
*bcpriv->pdev,
DMAMEM_TO_CPU,
@@ -310,16 +311,19 @@ int gr1553bc_list_table_alloc
if (bdtab_custom == NULL) {
/* Allocate descriptors */
list->_table = grlib_malloc(size + (GR1553BC_BD_ALIGN-1));
- if ( list->_table == NULL )
- return -1;
+ if ( list->_table == NULL ) {
+ retval = -1;
+ goto err;
+ }
+ /* 128-bit Alignment required by HW */
+ list->table_cpu =
+ (((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
+ ~(GR1553BC_BD_ALIGN-1));
} else {
/* Custom address, given in CPU-accessible address */
list->_table = bdtab_custom;
+ list->table_cpu = (unsigned int)list->_table;
}
- /* 128-bit Alignment required by HW */
- list->table_cpu =
- (((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
- ~(GR1553BC_BD_ALIGN-1));
/* We got CPU accessible descriptor table address, now we
* translate that into an address that the Hardware can
@@ -338,6 +342,12 @@ int gr1553bc_list_table_alloc
}
}
+ /* Verify alignment */
+ if (list->table_hw & (GR1553BC_BD_ALIGN-1)) {
+ retval = -2;
+ goto err;
+ }
+
/* Write End-Of-List all over the descriptor table here,
* For debugging/safety?
*/
@@ -359,8 +369,16 @@ int gr1553bc_list_table_alloc
table += gr1553bc_minor_table_size(major->minors[j]);
}
}
-
- return 0;
+err:
+ if (retval) {
+ if (list->_table_custom == NULL && list->_table) {
+ free(list->_table);
+ }
+ list->table_hw = 0;
+ list->table_cpu = 0;
+ list->_table = NULL;
+ }
+ return retval;
}
void gr1553bc_list_table_free(struct gr1553bc_list *list)
@@ -399,7 +417,7 @@ int gr1553bc_list_table_build(struct gr1553bc_list *list)
bds = minor->bds;
/* BD[0..SLOTCNT-1] = message slots
- * BD[SLOTCNT+0] = END
+ * BD[SLOTCNT+0] = END
* BD[SLOTCNT+1] = JUMP
*
* or if no optional time slot handling:
@@ -485,7 +503,7 @@ void gr1553bc_bd_init(
((word0 & GR1553BC_BD_TYPE) == 0) ) {
/* Don't touch timeslot previously allocated */
word0 &= ~GR1553BC_TR_TIME;
- word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
+ word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
GR1553BC_TR_TIME;
}
GR1553BC_WRITE_MEM(&raw->words[0], word0);
@@ -523,7 +541,7 @@ int gr1553bc_major_alloc_skel
maj->cfg = cfg;
maj->next = NULL;
- /* Create links between minor frames, and from minor frames
+ /* Create links between minor frames, and from minor frames
* to configuration structure.
*/
minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
@@ -697,7 +715,7 @@ int gr1553bc_slot_alloc2(
set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
/* Note: at the moment the minor frame can be executed faster
- * than expected, we hurry up writing requested
+ * than expected, we hurry up writing requested
* descriptor.
*/
}
@@ -886,7 +904,7 @@ int gr1553bc_slot_irq_prepare
union gr1553bc_bd *bd;
int slot_no, to_mid;
- /* Build unconditional IRQ descriptor. The padding is used
+ /* Build unconditional IRQ descriptor. The padding is used
* for identifying the MINOR frame and function and custom data.
*
* The IRQ is disabled at first, a unconditional jump to next
@@ -1115,7 +1133,7 @@ int gr1553bc_slot_update
*stat = GR1553BC_READ_MEM(&bd->tr.status);
if ( status ) {
/* Clear status fields user selects, then
- * or bit31 if user wants that. The bit31
+ * or bit31 if user wants that. The bit31
* may be used to indicate if the BC has
* performed the access.
*/
@@ -1192,7 +1210,7 @@ int gr1553bc_mid_from_bd(
found_mid:
/* Get MID of JUMP descriptor */
bdmid = word2 >> 8;
- /* Subtract distance from JUMP descriptor to find MID
+ /* Subtract distance from JUMP descriptor to find MID
* of requested BD.
*/
slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
@@ -1445,7 +1463,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
/* Stop BC if not already stopped */
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
- /* Since RT can not be used at the same time as BC, we stop
+ /* Since RT can not be used at the same time as BC, we stop
* RT rx, it should already be stopped...
*/
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
@@ -1463,7 +1481,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
priv->alist = NULL;
priv->irq_log_base = (uint32_t *)
- (((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
+ (((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
~(GR1553BC_IRQLOG_SIZE-1));
/* Translate into a hardware accessible address */
drvmgr_translate_check(
@@ -1487,7 +1505,7 @@ void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
/* Stop BC if not already stopped */
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
- /* Since RT can not be used at the same time as BC, we stop
+ /* Since RT can not be used at the same time as BC, we stop
* RT rx, it should already be stopped...
*/
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
@@ -1518,7 +1536,7 @@ void gr1553bc_isr(void *arg)
/* Clear handled IRQs */
GR1553BC_WRITE_REG(&priv->regs->irq, irq);
- /* DMA error. This IRQ does not affect the IRQ log.
+ /* DMA error. This IRQ does not affect the IRQ log.
* We let standard IRQ handle handle it.
*/
if ( irq & GR1553B_IRQEN_BCDE ) {
@@ -1563,7 +1581,7 @@ void gr1553bc_isr(void *arg)
bd = NULL;
}
- /* Handle Descriptor that cased IRQ
+ /* Handle Descriptor that cased IRQ
*
* If someone have inserted an IRQ descriptor and tied
* that to a custom function we call that function, otherwise
diff --git a/bsps/shared/grlib/1553/gr1553bm.c b/bsps/shared/grlib/1553/gr1553bm.c
index 482e574d78..0672c468a4 100644
--- a/bsps/shared/grlib/1553/gr1553bm.c
+++ b/bsps/shared/grlib/1553/gr1553bm.c
@@ -89,7 +89,7 @@ static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
/* Start logging */
priv->regs->bm_ctrl =
- (priv->cfg.filt_error_options &
+ (priv->cfg.filt_error_options &
(GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
| GR1553B_BM_CTRL_BMEN;
@@ -178,6 +178,7 @@ void gr1553bm_close(void *bm)
/* Configure the BM driver */
int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
{
+ int retval = 0;
struct gr1553bm_priv *priv = bm;
if ( priv->started )
@@ -193,12 +194,11 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
}
priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
if ((unsigned int)cfg->buffer_custom & 1) {
- /* Custom Address Given in Remote address. We need
- * to convert it intoTranslate into Hardware a
- * hardware accessible address
+ /* Custom address given in remote address. We need
+ * to convert it into a hardware accessible address
*/
- priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
- priv->buffer = cfg->buffer_custom;
+ priv->buffer = (void*)((unsigned int)cfg->buffer_custom & ~1);
+ priv->buffer_base_hw = (unsigned int)priv->buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -209,17 +209,19 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
if (cfg->buffer_custom == NULL) {
/* Allocate new buffer dynamically */
priv->buffer = grlib_malloc(priv->buffer_size + 8);
- if (priv->buffer == NULL)
- return -1;
+ if (priv->buffer == NULL) {
+ retval = -1;
+ goto err;
+ }
+ /* Align to 8 bytes */
+ priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) & ~(8-1);
} else {
/* Address given in CPU accessible address, no
* translation required.
*/
priv->buffer = cfg->buffer_custom;
+ priv->buffer_base = (unsigned int)priv->buffer;
}
- /* Align to 16 bytes */
- priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
- ~(8-1);
/* Translate address of buffer base into address that Hardware must
* use to access the buffer.
*/
@@ -229,13 +231,28 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
(void *)priv->buffer_base,
(void **)&priv->buffer_base_hw,
priv->buffer_size);
-
+
+ }
+
+ /* Verify alignment */
+ if (priv->buffer_base_hw & (8-1)) {
+ retval = -2;
+ goto err;
}
/* Copy valid config */
priv->cfg = *cfg;
- return 0;
+err:
+ if (retval) {
+ if (cfg->buffer_custom == NULL && priv->buffer) {
+ free(priv->buffer);
+ }
+ priv->buffer_base_hw = (unsigned int)NULL;
+ priv->buffer_base = (unsigned int)NULL;
+ priv->buffer = NULL;
+ }
+ return retval;
}
/* Start logging */
@@ -249,7 +266,7 @@ int gr1553bm_start(void *bm)
return -2;
/* Start at Time = 0 */
- priv->regs->bm_ttag =
+ priv->regs->bm_ttag =
priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
/* Configure Filters */
@@ -282,7 +299,7 @@ void gr1553bm_stop(void *bm)
/* Stop Hardware */
gr1553bm_hw_stop(priv);
- /* At this point the hardware must be stopped and IRQ
+ /* At this point the hardware must be stopped and IRQ
* sources unmasked.
*/
@@ -331,7 +348,7 @@ resample:
hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
if ( hwtime > hwtime2 ) {
/* priv->time and hwtime may be out of sync if
- * IRQ updated priv->time just after bm_ttag was read
+ * IRQ updated priv->time just after bm_ttag was read
* here, we resample if we detect inconsistancy.
*/
goto resample;
diff --git a/bsps/shared/grlib/1553/gr1553rt.c b/bsps/shared/grlib/1553/gr1553rt.c
index 339e856c76..7f35138376 100644
--- a/bsps/shared/grlib/1553/gr1553rt.c
+++ b/bsps/shared/grlib/1553/gr1553rt.c
@@ -147,7 +147,6 @@ static int gr1553rt_list_reg(struct gr1553rt_list *list)
return -1;
}
-#if 0 /* unused for now */
/* Unregister List from device */
static void gr1553rt_list_unreg(struct gr1553rt_list *list)
{
@@ -156,16 +155,15 @@ static void gr1553rt_list_unreg(struct gr1553rt_list *list)
priv->lists[list->listid] = NULL;
list->listid = -1;
}
-#endif
static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
{
struct gr1553rt_priv *priv = rt;
-
+
unsigned short index;
/* Get Index of Software BD */
- index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
+ index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
sizeof(struct gr1553rt_sw_bd);
return index;
@@ -197,10 +195,9 @@ static int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
}
*bd = &priv->swbds[priv->swbd_free];
+ curr = &priv->swbds[priv->swbd_free];
for (i=0; i<cnt; i++) {
- if ( i == 0) {
- curr = &priv->swbds[priv->swbd_free];
- } else {
+ if ( i != 0) {
curr = &priv->swbds[curr->this_next];
}
if ( curr->this_next == 0xffff ) {
@@ -240,7 +237,7 @@ int gr1553rt_list_init
{
struct gr1553rt_priv *priv = rt;
size_t size;
- int i;
+ int i, malloc_used;
struct gr1553rt_sw_bd *swbd;
unsigned short index;
struct gr1553rt_list *list;
@@ -251,6 +248,7 @@ int gr1553rt_list_init
* If the IN/OUT plist argument points to NULL a list
* dynamically allocated here.
*/
+ malloc_used = 0;
list = *plist;
if ( list == NULL ) {
/* Dynamically allocate LIST */
@@ -258,20 +256,27 @@ int gr1553rt_list_init
(cfg->bd_cnt * sizeof(list->bds[0]));
list = grlib_malloc(size);
if ( list == NULL )
- return -1;
+ return -1; /* Out of Memory */
*plist = list;
+ malloc_used = 1;
}
list->rt = rt;
list->subadr = -1;
list->listid = gr1553rt_list_reg(list);
- if ( list->listid == -1 )
+ if ( list->listid == -1 ) {
+ if (malloc_used)
+ free(list);
return -2; /* Too many lists */
+ }
list->cfg = cfg;
list->bd_cnt = cfg->bd_cnt;
/* Allocate all BDs needed by list */
if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
+ gr1553rt_list_unreg(list);
+ if (malloc_used)
+ free(list);
return -3; /* Too few descriptors */
}
@@ -352,7 +357,7 @@ int gr1553rt_bd_init(
bd->next = nextbd;
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
- return 0;
+ return 0;
}
int gr1553rt_bd_update(
@@ -410,7 +415,7 @@ int gr1553rt_bd_update(
}
*dptr = (uint16_t *)tmp;
}
- SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return 0;
}
@@ -727,7 +732,7 @@ void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
/* Stop BC if not already stopped: BC can not be used simultaneously
- * as the RT anyway
+ * as the RT anyway
*/
GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
@@ -766,17 +771,17 @@ void gr1553rt_sw_free(struct gr1553rt_priv *priv)
}
}
-/* Free dynamically allocated buffers, if any */
static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
{
int size;
+ int retval = 0;
/* Allocate Event log */
if ((unsigned int)priv->cfg.evlog_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
- priv->evlog_hw_base = (unsigned int *)
+ priv->evlog_buffer = (void *)
((unsigned int)priv->cfg.evlog_buffer & ~0x1);
- priv->evlog_buffer = priv->cfg.evlog_buffer;
+ priv->evlog_hw_base = (unsigned int*)priv->evlog_buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -788,16 +793,19 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
if (priv->cfg.evlog_buffer == NULL) {
priv->evlog_buffer = grlib_malloc(
priv->cfg.evlog_size * 2);
- if (priv->evlog_buffer == NULL)
- return -1;
+ if (priv->evlog_buffer == NULL) {
+ retval = -1;
+ goto err;
+ }
+ /* Align to SIZE bytes boundary */
+ priv->evlog_cpu_base = (unsigned int *)
+ (((unsigned int)priv->evlog_buffer +
+ (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
} else {
/* Addess already CPU-LOCAL */
priv->evlog_buffer = priv->cfg.evlog_buffer;
+ priv->evlog_cpu_base = (unsigned int *)priv->evlog_buffer;
}
- /* Align to SIZE bytes boundary */
- priv->evlog_cpu_base = (unsigned int *)
- (((unsigned int)priv->evlog_buffer +
- (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
drvmgr_translate_check(
*priv->pdev,
@@ -807,6 +815,11 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
priv->cfg.evlog_size
);
}
+ /* Verify alignment */
+ if ((unsigned int)priv->evlog_hw_base & (priv->cfg.evlog_size-1)) {
+ retval = -2;
+ goto err;
+ }
priv->evlog_cpu_end = priv->evlog_cpu_base +
priv->cfg.evlog_size/sizeof(unsigned int *);
@@ -815,9 +828,9 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
if ((unsigned int)priv->cfg.bd_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
- priv->bds_hw = (struct gr1553rt_bd *)
+ priv->bd_buffer = (void *)
((unsigned int)priv->cfg.bd_buffer & ~0x1);
- priv->bd_buffer = priv->cfg.bd_buffer;
+ priv->bds_hw = (struct gr1553rt_bd *)priv->bd_buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -828,15 +841,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
} else {
if ( priv->cfg.bd_buffer == NULL ) {
priv->bd_buffer = grlib_malloc(size + 0xf);
- if (priv->bd_buffer == NULL)
- return -1;
+ if (priv->bd_buffer == NULL) {
+ retval = -1;
+ goto err;
+ }
+ /* Align to 16 bytes boundary */
+ priv->bds_cpu = (struct gr1553rt_bd *)
+ (((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
} else {
/* Addess already CPU-LOCAL */
priv->bd_buffer = priv->cfg.bd_buffer;
+ priv->bds_cpu = (struct gr1553rt_bd *)priv->bd_buffer;
}
- /* Align to 16 bytes boundary */
- priv->bds_cpu = (struct gr1553rt_bd *)
- (((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
/* Translate from CPU address to hardware address */
drvmgr_translate_check(
@@ -847,21 +863,28 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
size
);
}
+ /* Verify alignment */
+ if ((unsigned int)priv->bds_hw & (0xf)) {
+ retval = -2;
+ goto err;
+ }
#if (RTBD_MAX == 0)
/* Allocate software description of */
priv->swbds = grlib_malloc(priv->cfg.bd_count * sizeof(*priv->swbds));
if ( priv->swbds == NULL ) {
- return -1;
+ retval = -1;
+ goto err;
}
#endif
/* Allocate Sub address table */
if ((unsigned int)priv->cfg.satab_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
- priv->sas_hw = (struct gr1553rt_sa *)
+ priv->satab_buffer = (void *)
((unsigned int)priv->cfg.satab_buffer & ~0x1);
- priv->satab_buffer = priv->cfg.satab_buffer;
+ priv->sas_hw = (struct gr1553rt_sa *)priv->satab_buffer;
+
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -871,16 +894,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
} else {
if (priv->cfg.satab_buffer == NULL) {
priv->satab_buffer = grlib_malloc((16 * 32) * 2);
- if (priv->satab_buffer == NULL)
- return -1;
+ if (priv->satab_buffer == NULL) {
+ retval = -1;
+ goto err;
+ }
+ /* Align to 512 bytes boundary */
+ priv->sas_cpu = (struct gr1553rt_sa *)
+ (((unsigned int)priv->satab_buffer + 0x1ff) & ~0x1ff);
} else {
/* Addess already CPU-LOCAL */
priv->satab_buffer = priv->cfg.satab_buffer;
+ priv->sas_cpu = (struct gr1553rt_sa *)priv->satab_buffer;
}
- /* Align to 512 bytes boundary */
- priv->sas_cpu = (struct gr1553rt_sa *)
- (((unsigned int)priv->satab_buffer + 0x1ff) &
- ~0x1ff);
/* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
drvmgr_translate_check(
@@ -890,8 +915,17 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
(void **)&priv->sas_hw,
16 * 32);
}
+ /* Verify alignment */
+ if ((unsigned int)priv->sas_hw & (0x1ff)) {
+ retval = -2;
+ goto err;
+ }
- return 0;
+err:
+ if (retval) {
+ gr1553rt_sw_free(priv);
+ }
+ return retval;
}
void gr1553rt_sw_init(struct gr1553rt_priv *priv)
@@ -937,7 +971,7 @@ void gr1553rt_sw_init(struct gr1553rt_priv *priv)
int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
{
struct gr1553rt_priv *priv = rt;
-
+ int retval = 0;
if ( priv->started )
return -1;
@@ -949,9 +983,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
if ( cfg->rtaddress > 30 )
return -1;
if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
- return -1; /* SIZE: Not aligned to a power of 2 */
+ return -2; /* SIZE: Not aligned to a power of 2 */
if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
- return -1; /* Buffer: Not aligned to size */
+ return -2; /* Buffer: Not aligned to size */
#if (RTBD_MAX > 0)
if ( cfg->bd_count > RTBD_MAX )
return -1;
@@ -962,8 +996,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
/*** Adapt to new config ***/
- if ( gr1553rt_sw_alloc(priv) != 0 )
- return -1;
+ if ( (retval=gr1553rt_sw_alloc(priv)) != 0 ) {
+ return retval;
+ }
gr1553rt_sw_init(priv);
diff --git a/bsps/shared/grlib/amba/ahbstat.c b/bsps/shared/grlib/amba/ahbstat.c
index af3d778feb..3ab0262e1e 100644
--- a/bsps/shared/grlib/amba/ahbstat.c
+++ b/bsps/shared/grlib/amba/ahbstat.c
@@ -46,12 +46,20 @@ int (*ahbstat_error)(
uint32_t failing_address
) __attribute__((weak)) = NULL;
+#define AHBSTAT_STS_ME_BIT 13
+#define AHBSTAT_STS_FW_BIT 12
+#define AHBSTAT_STS_CF_BIT 11
+#define AHBSTAT_STS_AF_BIT 10
#define AHBSTAT_STS_CE_BIT 9
#define AHBSTAT_STS_NE_BIT 8
#define AHBSTAT_STS_HW_BIT 7
#define AHBSTAT_STS_HM_BIT 3
#define AHBSTAT_STS_HS_BIT 0
+#define AHBSTAT_STS_ME (1 << AHBSTAT_STS_ME_BIT)
+#define AHBSTAT_STS_FW (1 << AHBSTAT_STS_FW_BIT)
+#define AHBSTAT_STS_CF (1 << AHBSTAT_STS_CF_BIT)
+#define AHBSTAT_STS_AF (1 << AHBSTAT_STS_AF_BIT)
#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
diff --git a/bsps/shared/grlib/amba/ambapp_names.c b/bsps/shared/grlib/amba/ambapp_names.c
index 8d168f283b..4ccb0621e6 100644
--- a/bsps/shared/grlib/amba/ambapp_names.c
+++ b/bsps/shared/grlib/amba/ambapp_names.c
@@ -199,7 +199,26 @@ static ambapp_device_name GAISLER_devices[] =
{GAISLER_TCCOP, "TCCOP"},
{GAISLER_SPIMASTER, "SPIMASTER"},
{GAISLER_SPISLAVE, "SPISLAVE"},
- {GAISLER_GRSRIO, "GRSRIO"},
+ {GAISLER_GRSRIO, "GRSRIO"},
+ {GAISLER_AHBLM2AHB, "AHBLM2AHB"},
+ {GAISLER_AHBS2NOC, "AHBS2NOC"},
+ {GAISLER_TCAU, "TCAU"},
+ {GAISLER_GRTMDYNVCID, "GRTMDYNVCID"},
+ {GAISLER_RNOCIRQPROP, "RNOCIRQPROP"},
+ {GAISLER_FTADDR, "FTADDR"},
+ {GAISLER_ATG, "ATG"},
+ {GAISLER_DFITRACE, "DFITRACE"},
+ {GAISLER_SELFTEST, "SELFTEST"},
+ {GAISLER_DFIERRINJ, "DFIERRINJ"},
+ {GAISLER_DFICHECK, "DFICHECK"},
+ {GAISLER_GRCANFD, "GRCANFD"},
+ {GAISLER_NIM, "NIM"},
+ {GAISLER_BANDGAP, "BANDGAP"},
+ {GAISLER_MPROT, "MPROT"},
+ {GAISLER_ADC, "ADC"},
+ {GAISLER_BO, "BO"},
+ {GAISLER_DAC, "DAC"},
+ {GAISLER_PLL, "PLL"},
{0, NULL}
};
diff --git a/bsps/shared/grlib/btimer/tlib_ckinit.c b/bsps/shared/grlib/btimer/tlib_ckinit.c
index 4f679984d8..5ac325052c 100644
--- a/bsps/shared/grlib/btimer/tlib_ckinit.c
+++ b/bsps/shared/grlib/btimer/tlib_ckinit.c
@@ -209,15 +209,14 @@ static uint32_t simple_tlib_tc_get_timecount(struct timecounter *tc)
static rtems_device_driver simple_initialize_counter(void)
{
- uint64_t frequency;
- unsigned int tick_hz;
+ unsigned int tick_hz, frequency;
- frequency = 1000000;
+ tlib_get_freq(priv.tlib_tick, &frequency, NULL);
tick_hz = rtems_configuration_get_microseconds_per_tick();
rtems_timecounter_simple_install(
&priv.tc_simple,
- frequency,
+ (uint64_t)frequency,
tick_hz,
simple_tlib_tc_get_timecount
);
diff --git a/bsps/shared/grlib/can/canbtrs.c b/bsps/shared/grlib/can/canbtrs.c
new file mode 100644
index 0000000000..307547475c
--- /dev/null
+++ b/bsps/shared/grlib/can/canbtrs.c
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup can
+ *
+ * @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
+ *
+ * Implements common routines for calculating CAN baud-rate parameters from
+ * a user provided baud-rate speed.
+ */
+
+/*
+ * Copyright (C) 2019, 2020 Cobham Gailer AB
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <grlib/canbtrs.h>
+
+/*#define GRLIB_CANBTRS_DEBUG*/
+
+/* Calculate CAN baud-rate generation parameters from requested baud-rate */
+int grlib_canbtrs_calc_timing(
+ unsigned int baud,
+ unsigned int core_hz,
+ unsigned int sampl_pt,
+ struct grlib_canbtrs_ranges *br,
+ struct grlib_canbtrs_timing *timing
+ )
+{
+ int best_error = 2000000000, best_tseg=0, best_scaler=0;
+ int tseg=0, tseg1=0, tseg2=0, sc, tmp, error;
+
+ /* Default to 80% sample point */
+ if ((sampl_pt < 50) || (sampl_pt > 99))
+ sampl_pt = 80;
+
+ /* step though all TSEG1+TSEG2 values possible */
+ for (tseg = (br->min_tseg1 + br->min_tseg2);
+ tseg <= (br->max_tseg1 + br->max_tseg2);
+ tseg++) {
+ /* calculate scaler */
+ tmp = ((br->divfactor + tseg) * baud);
+ sc = (core_hz * 2)/ tmp - core_hz / tmp;
+ if (sc <= 0 || sc > br->max_scaler)
+ continue;
+ if (br->has_bpr &&
+ (((sc > 256 * 1) && (sc <= 256 * 2) && (sc & 0x1)) ||
+ ((sc > 256 * 2) && (sc <= 256 * 4) && (sc & 0x3)) ||
+ ((sc > 256 * 4) && (sc <= 256 * 8) && (sc & 0x7))))
+ continue;
+
+ error = baud - core_hz / (sc * (br->divfactor + tseg));
+#ifdef GRLIB_CANBTRS_DEBUG
+ printf(" baud=%d, tseg=%d, sc=%d, error=%d\n",
+ baud, tseg, sc, error);
+#endif
+ if (error < 0)
+ error = -error;
+
+ /* tseg is increasing, so we accept higher tseg with the same
+ * baudrate to get better sampling point.
+ */
+ if (error <= best_error) {
+ best_error = error;
+ best_tseg = tseg;
+ best_scaler = sc;
+#ifdef GRLIB_CANBTRS_DEBUG
+ printf(" ! best baud=%d\n",
+ core_hz/(sc * (br->divfactor + tseg)));
+#endif
+ }
+ }
+
+ /* return an error if 5% off baud-rate */
+ if (best_error && (baud / best_error <= 5)) {
+ return -2;
+ } else if (!timing) {
+ return 0; /* nothing to store result in, but a valid bitrate can be calculated */
+ }
+
+ tseg2 = (best_tseg + br->divfactor) -
+ ((sampl_pt * (best_tseg + br->divfactor)) / 100);
+ if (tseg2 < br->min_tseg2) {
+ tseg2 = br->min_tseg2;
+ } else if (tseg2 > br->max_tseg2) {
+ tseg2 = br->max_tseg2;
+ }
+
+ tseg1 = best_tseg - tseg2;
+ if (tseg1 > br->max_tseg1) {
+ tseg1 = br->max_tseg1;
+ tseg2 = best_tseg - tseg1;
+ } else if (tseg1 < br->min_tseg1) {
+ tseg1 = br->min_tseg1;
+ tseg2 = best_tseg - tseg1;
+ }
+
+ /* Get scaler and BPR from pseudo SCALER clock */
+ if (best_scaler <= 256) {
+ timing->scaler = best_scaler - 1;
+ timing->bpr = 0;
+ } else if (best_scaler <= 256 * 2) {
+ timing->scaler = ((best_scaler + 1) >> 1) - 1;
+ timing->bpr = 1;
+ } else if (best_scaler <= 256 * 4) {
+ timing->scaler = ((best_scaler + 1) >> 2) - 1;
+ timing->bpr = 2;
+ } else {
+ timing->scaler = ((best_scaler + 1) >> 3) - 1;
+ timing->bpr = 3;
+ }
+
+ timing->ps1 = tseg1;
+ timing->ps2 = tseg2;
+ timing->rsj = 1;
+
+#ifdef GRLIB_CANBTRS_DEBUG
+ printf(" ! result: sc=%d,bpr=%d,ps1=%d,ps2=%d\n", timing->scaler, timing->bpr, timing->ps1, timing->ps2);
+#endif
+
+ return 0;
+}
diff --git a/bsps/shared/grlib/can/grcan.c b/bsps/shared/grlib/can/grcan.c
index d69d99d85a..69f64cc285 100644
--- a/bsps/shared/grlib/can/grcan.c
+++ b/bsps/shared/grlib/can/grcan.c
@@ -1,7 +1,7 @@
/*
* GRCAN driver
*
- * COPYRIGHT (c) 2007.
+ * COPYRIGHT (c) 2007-2019.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
@@ -18,18 +18,17 @@
#include <rtems/bspIo.h>
#include <grlib/grcan.h>
+#include <grlib/canbtrs.h>
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/ambapp.h>
#include <grlib/grlib_impl.h>
+#include "grcan_internal.h"
/* Maximum number of GRCAN devices supported by driver */
#define GRCAN_COUNT_MAX 8
-#define WRAP_AROUND_TX_MSGS 1
-#define WRAP_AROUND_RX_MSGS 2
-#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
#define BLOCK_SIZE (16*4)
/* grcan needs to have it buffers aligned to 1k boundaries */
@@ -57,15 +56,6 @@
#define IRQ_MASK(irqno)
#endif
-#ifndef GRCAN_DEFAULT_BAUD
- /* default to 500kbits/s */
- #define GRCAN_DEFAULT_BAUD 500000
-#endif
-
-#ifndef GRCAN_SAMPLING_POINT
- #define GRCAN_SAMPLING_POINT 80
-#endif
-
/* Uncomment for debug output */
/****************** DEBUG Definitions ********************/
#define DBG_TX 2
@@ -88,70 +78,10 @@ int state2err[4] = {
/* STATE_AHBERR */ GRCAN_RET_AHBERR
};
-struct grcan_msg {
- unsigned int head[2];
- unsigned char data[8];
-};
-
-struct grcan_config {
- struct grcan_timing timing;
- struct grcan_selection selection;
- int abort;
- int silent;
-};
-
-struct grcan_priv {
- struct drvmgr_dev *dev; /* Driver manager device */
- char devName[32]; /* Device Name */
- unsigned int baseaddr, ram_base;
- struct grcan_regs *regs;
- int irq;
- int minor;
- int open;
- int started;
- unsigned int channel;
- int flushing;
- unsigned int corefreq_hz;
-
- /* Circular DMA buffers */
- void *_rx, *_rx_hw;
- void *_tx, *_tx_hw;
- void *txbuf_adr;
- void *rxbuf_adr;
- struct grcan_msg *rx;
- struct grcan_msg *tx;
- unsigned int rxbuf_size; /* requested RX buf size in bytes */
- unsigned int txbuf_size; /* requested TX buf size in bytes */
-
- int txblock, rxblock;
- int txcomplete, rxcomplete;
-
- struct grcan_filter sfilter;
- struct grcan_filter afilter;
- int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
- struct grcan_config config;
- struct grcan_stats stats;
-
- rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
- SPIN_DECLARE(devlock);
-};
-
static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
-static int grcan_hw_read_try(
- struct grcan_priv *pDev,
- struct grcan_regs *regs,
- CANMsg *buffer,
- int max);
-
-static int grcan_hw_write_try(
- struct grcan_priv *pDev,
- struct grcan_regs *regs,
- CANMsg *buffer,
- int count);
-
static void grcan_hw_config(
- struct grcan_regs *regs,
+ struct grcan_priv *pDev,
struct grcan_config *conf);
static void grcan_hw_accept(
@@ -164,21 +94,40 @@ static void grcan_hw_sync(
static void grcan_interrupt(void *arg);
-#ifdef GRCAN_REG_BYPASS_CACHE
-#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
-#else
-#define READ_REG(address) (*(volatile unsigned int *)(address))
-#endif
+#define NELEM(a) ((int) (sizeof (a) / sizeof (a[0])))
-#ifdef GRCAN_DMA_BYPASS_CACHE
-#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
-#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
-#else
-#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
-#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
-#endif
+/* GRCAN nominal boundaries for baud-rate paramters */
+struct grlib_canbtrs_ranges grcan_btrs_ranges = {
+ .max_scaler = 256*8, /* scaler is multiplied by BPR in steps 1,2,4,8 */
+ .has_bpr = 1,
+ .divfactor = 2,
+ .min_tseg1 = 1,
+ .max_tseg1 = 15,
+ .min_tseg2 = 2,
+ .max_tseg2 = 8,
+};
-#define NELEM(a) ((int) (sizeof (a) / sizeof (a[0])))
+/* GRCANFD nominal boundaries */
+struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges = {
+ .max_scaler = 256,
+ .has_bpr = 0,
+ .divfactor = 1,
+ .min_tseg1 = 2,
+ .max_tseg1 = 63,
+ .min_tseg2 = 2,
+ .max_tseg2 = 16,
+};
+
+/* GRCANFD flexible baud-rate boundaries */
+struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges = {
+ .max_scaler = 256,
+ .has_bpr = 0,
+ .divfactor = 1,
+ .min_tseg1 = 1,
+ .max_tseg1 = 15,
+ .min_tseg2 = 2,
+ .max_tseg2 = 8,
+};
static int grcan_count = 0;
static struct grcan_priv *priv_tab[GRCAN_COUNT_MAX];
@@ -202,6 +151,7 @@ struct amba_dev_id grcan_ids[] =
{
{VENDOR_GAISLER, GAISLER_GRCAN},
{VENDOR_GAISLER, GAISLER_GRHCAN},
+ {VENDOR_GAISLER, GAISLER_GRCANFD},
{0, 0} /* Mark end of table */
};
@@ -294,6 +244,8 @@ int grcan_device_init(struct grcan_priv *pDev)
pDev->irq = pnpinfo->irq;
pDev->regs = (struct grcan_regs *)pnpinfo->apb_slv->start;
pDev->minor = pDev->dev->minor_drv;
+ if (ambadev->id.device == GAISLER_GRCANFD)
+ pDev->fd_capable = 1;
/* Get frequency in Hz */
if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) {
@@ -373,7 +325,7 @@ static rtems_device_driver grcan_hw_start(struct grcan_priv *pDev)
* and Setup timing
*/
if (pDev->config_changed) {
- grcan_hw_config(pDev->regs, &pDev->config);
+ grcan_hw_config(pDev, &pDev->config);
pDev->config_changed = 0;
}
@@ -456,9 +408,10 @@ static void grcan_sw_stop(struct grcan_priv *pDev)
rtems_semaphore_release(pDev->txempty_sem);
}
-static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
+static void grcan_hw_config(struct grcan_priv *pDev, struct grcan_config *conf)
{
unsigned int config = 0;
+ struct grcan_regs *regs = pDev->regs;
/* Reset HurriCANe Core */
regs->ctrl = 0;
@@ -479,13 +432,29 @@ static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
config |= GRCAN_CFG_ENABLE1;
/* Timing */
- config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) & GRCAN_CFG_BPR;
- config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) & GRCAN_CFG_RSJ;
- config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) & GRCAN_CFG_PS1;
- config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) & GRCAN_CFG_PS2;
- config |=
- (conf->timing.scaler << GRCAN_CFG_SCALER_BIT) & GRCAN_CFG_SCALER;
-
+ if (!pDev->fd_capable) {
+ config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) &
+ GRCAN_CFG_BPR;
+ config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) &
+ GRCAN_CFG_RSJ;
+ config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) &
+ GRCAN_CFG_PS1;
+ config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) &
+ GRCAN_CFG_PS2;
+ config |= (conf->timing.scaler << GRCAN_CFG_SCALER_BIT) &
+ GRCAN_CFG_SCALER;
+ } else {
+ regs->nbtr =
+ (conf->timing.scaler << GRCANFD_NBTR_SCALER_BIT) |
+ (conf->timing.ps1 << GRCANFD_NBTR_PS1_BIT) |
+ (conf->timing.ps2 << GRCANFD_NBTR_PS2_BIT) |
+ (conf->timing.rsj << GRCANFD_NBTR_SJW_BIT);
+ regs->fdbtr =
+ (conf->timing_fd.scaler << GRCANFD_FDBTR_SCALER_BIT) |
+ (conf->timing_fd.ps1 << GRCANFD_FDBTR_PS1_BIT) |
+ (conf->timing_fd.ps2 << GRCANFD_FDBTR_PS2_BIT) |
+ (conf->timing_fd.sjw << GRCANFD_FDBTR_SJW_BIT);
+ }
/* Write configuration */
regs->conf = config;
@@ -520,338 +489,7 @@ static void grcan_hw_sync(struct grcan_regs *regs, struct grcan_filter *sfilter)
regs->smask = sfilter->mask;
}
-static unsigned int grcan_hw_rxavail(
- unsigned int rp,
- unsigned int wp, unsigned int size
-)
-{
- if (rp == wp) {
- /* read pointer and write pointer is equal only
- * when RX buffer is empty.
- */
- return 0;
- }
-
- if (wp > rp) {
- return (wp - rp) / GRCAN_MSG_SIZE;
- } else {
- return (size - (rp - wp)) / GRCAN_MSG_SIZE;
- }
-}
-
-static unsigned int grcan_hw_txspace(
- unsigned int rp,
- unsigned int wp,
- unsigned int size
-)
-{
- unsigned int left;
-
- if (rp == wp) {
- /* read pointer and write pointer is equal only
- * when TX buffer is empty.
- */
- return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
- }
-
- /* size - 4 - abs(read-write) */
- if (wp > rp) {
- left = size - (wp - rp);
- } else {
- left = rp - wp;
- }
-
- return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
-}
-
-#define MIN_TSEG1 1
-#define MIN_TSEG2 2
-#define MAX_TSEG1 14
-#define MAX_TSEG2 8
-
-static int grcan_calc_timing(
- unsigned int baud, /* The requested BAUD to calculate timing for */
- unsigned int core_hz, /* Frequency in Hz of GRCAN Core */
- unsigned int sampl_pt,
- struct grcan_timing *timing /* result is placed here */
-)
-{
- int best_error = 1000000000;
- int error;
- int best_tseg = 0, best_brp = 0, brp = 0;
- int tseg = 0, tseg1 = 0, tseg2 = 0;
- int sjw = 1;
-
- /* Default to 90% */
- if ((sampl_pt < 50) || (sampl_pt > 99)) {
- sampl_pt = GRCAN_SAMPLING_POINT;
- }
-
- if ((baud < 5000) || (baud > 1000000)) {
- /* invalid speed mode */
- return -1;
- }
-
- /* find best match, return -2 if no good reg
- * combination is available for this frequency
- */
-
- /* some heuristic specials */
- if (baud > ((1000000 + 500000) / 2))
- sampl_pt = 75;
-
- if (baud < ((12500 + 10000) / 2))
- sampl_pt = 75;
-
- /* tseg even = round down, odd = round up */
- for (
- tseg = (MIN_TSEG1 + MIN_TSEG2 + 2) * 2;
- tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
- tseg++
- ) {
- brp = core_hz / ((1 + tseg / 2) * baud) + tseg % 2;
- if (
- (brp <= 0) ||
- ((brp > 256 * 1) && (brp <= 256 * 2) && (brp & 0x1)) ||
- ((brp > 256 * 2) && (brp <= 256 * 4) && (brp & 0x3)) ||
- ((brp > 256 * 4) && (brp <= 256 * 8) && (brp & 0x7)) ||
- (brp > 256 * 8)
- )
- continue;
-
- error = baud - core_hz / (brp * (1 + tseg / 2));
- if (error < 0) {
- error = -error;
- }
-
- if (error <= best_error) {
- best_error = error;
- best_tseg = tseg / 2;
- best_brp = brp - 1;
- }
- }
-
- if (best_error && (baud / best_error < 10)) {
- return -2;
- } else if (!timing)
- return 0; /* nothing to store result in, but a valid bitrate can be calculated */
-
- tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
-
- if (tseg2 < MIN_TSEG2) {
- tseg2 = MIN_TSEG2;
- }
-
- if (tseg2 > MAX_TSEG2) {
- tseg2 = MAX_TSEG2;
- }
-
- tseg1 = best_tseg - tseg2 - 2;
-
- if (tseg1 > MAX_TSEG1) {
- tseg1 = MAX_TSEG1;
- tseg2 = best_tseg - tseg1 - 2;
- }
-
- /* Get scaler and BRP from pseudo BRP */
- if (best_brp <= 256) {
- timing->scaler = best_brp;
- timing->bpr = 0;
- } else if (best_brp <= 256 * 2) {
- timing->scaler = ((best_brp + 1) >> 1) - 1;
- timing->bpr = 1;
- } else if (best_brp <= 256 * 4) {
- timing->scaler = ((best_brp + 1) >> 2) - 1;
- timing->bpr = 2;
- } else {
- timing->scaler = ((best_brp + 1) >> 3) - 1;
- timing->bpr = 3;
- }
-
- timing->ps1 = tseg1 + 1;
- timing->ps2 = tseg2;
- timing->rsj = sjw;
-
- return 0;
-}
-
-static int grcan_hw_read_try(
- struct grcan_priv *pDev,
- struct grcan_regs *regs,
- CANMsg * buffer,
- int max
-)
-{
- int i, j;
- CANMsg *dest;
- struct grcan_msg *source, tmp;
- unsigned int wp, rp, size, rxmax, addr;
- int trunk_msg_cnt;
-
- FUNCDBG();
-
- wp = READ_REG(&regs->rx0wr);
- rp = READ_REG(&regs->rx0rd);
-
- /*
- * Due to hardware wrap around simplification write pointer will
- * never reach the read pointer, at least a gap of 8 bytes.
- * The only time they are equal is when the read pointer has
- * reached the write pointer (empty buffer)
- *
- */
- if (wp != rp) {
- /* Not empty, we have received chars...
- * Read as much as possible from DMA buffer
- */
- size = READ_REG(&regs->rx0size);
-
- /* Get number of bytes available in RX buffer */
- trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
-
- /* truncate size if user space buffer hasn't room for
- * all received chars.
- */
- if (trunk_msg_cnt > max)
- trunk_msg_cnt = max;
-
- /* Read until i is 0 */
- i = trunk_msg_cnt;
-
- addr = (unsigned int)pDev->rx;
- source = (struct grcan_msg *)(addr + rp);
- dest = buffer;
- rxmax = addr + (size - GRCAN_MSG_SIZE);
-
- /* Read as many can messages as possible */
- while (i > 0) {
- /* Read CAN message from DMA buffer */
- tmp.head[0] = READ_DMA_WORD(&source->head[0]);
- tmp.head[1] = READ_DMA_WORD(&source->head[1]);
- if (tmp.head[1] & 0x4) {
- DBGC(DBG_RX, "overrun\n");
- }
- if (tmp.head[1] & 0x2) {
- DBGC(DBG_RX, "bus-off mode\n");
- }
- if (tmp.head[1] & 0x1) {
- DBGC(DBG_RX, "error-passive mode\n");
- }
- /* Convert one grcan CAN message to one "software" CAN message */
- dest->extended = tmp.head[0] >> 31;
- dest->rtr = (tmp.head[0] >> 30) & 0x1;
- if (dest->extended) {
- dest->id = tmp.head[0] & 0x3fffffff;
- } else {
- dest->id = (tmp.head[0] >> 18) & 0xfff;
- }
- dest->len = tmp.head[1] >> 28;
- for (j = 0; j < dest->len; j++)
- dest->data[j] = READ_DMA_BYTE(&source->data[j]);
-
- /* wrap around if neccessary */
- source =
- ((unsigned int)source >= rxmax) ?
- (struct grcan_msg *)addr : source + 1;
- dest++; /* straight user buffer */
- i--;
- }
- {
- /* A bus off interrupt may have occured after checking pDev->started */
- SPIN_IRQFLAGS(oldLevel);
-
- SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
- if (pDev->started == STATE_STARTED) {
- regs->rx0rd = (unsigned int) source - addr;
- regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
- } else {
- DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
- trunk_msg_cnt = state2err[pDev->started];
- }
- SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
- }
- return trunk_msg_cnt;
- }
- return 0;
-}
-
-static int grcan_hw_write_try(
- struct grcan_priv *pDev,
- struct grcan_regs *regs,
- CANMsg * buffer,
- int count
-)
-{
- unsigned int rp, wp, size, txmax, addr;
- int ret;
- struct grcan_msg *dest;
- CANMsg *source;
- int space_left;
- unsigned int tmp;
- int i;
-
- DBGC(DBG_TX, "\n");
- /*FUNCDBG(); */
-
- rp = READ_REG(&regs->tx0rd);
- wp = READ_REG(&regs->tx0wr);
- size = READ_REG(&regs->tx0size);
-
- space_left = grcan_hw_txspace(rp, wp, size);
-
- /* is circular fifo full? */
- if (space_left < 1)
- return 0;
-
- /* Truncate size */
- if (space_left > count)
- space_left = count;
- ret = space_left;
-
- addr = (unsigned int)pDev->tx;
-
- dest = (struct grcan_msg *)(addr + wp);
- source = (CANMsg *) buffer;
- txmax = addr + (size - GRCAN_MSG_SIZE);
-
- while (space_left > 0) {
- /* Convert and write CAN message to DMA buffer */
- if (source->extended) {
- tmp = (1 << 31) | (source->id & 0x3fffffff);
- } else {
- tmp = (source->id & 0xfff) << 18;
- }
- if (source->rtr)
- tmp |= (1 << 30);
- dest->head[0] = tmp;
- dest->head[1] = source->len << 28;
- for (i = 0; i < source->len; i++)
- dest->data[i] = source->data[i];
- source++; /* straight user buffer */
- dest =
- ((unsigned int)dest >= txmax) ?
- (struct grcan_msg *)addr : dest + 1;
- space_left--;
- }
-
- {
- /* A bus off interrupt may have occured after checking pDev->started */
- SPIN_IRQFLAGS(oldLevel);
-
- SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
- if (pDev->started == STATE_STARTED) {
- regs->tx0wr = (unsigned int) dest - addr;
- regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
- } else {
- DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
- ret = state2err[pDev->started];
- }
- SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
- }
- return ret;
-}
-
-static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
+int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
{
unsigned int wp, rp, size, irq;
unsigned int irq_trunk, dataavail;
@@ -934,7 +572,7 @@ static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
* min must be at least WRAP_AROUND_TX_MSGS less than max buffer capacity
* (pDev->txbuf_size/GRCAN_MSG_SIZE) for this algo to work.
*/
-static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
+int grcan_wait_txspace(struct grcan_priv *pDev, int min)
{
int wait, state;
unsigned int irq, rp, wp, size, space_left;
@@ -1007,7 +645,7 @@ static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
return state2err[pDev->started];
}
- /* At this point the TxIRQ has been masked, we ned not to mask it */
+ /* At this point the TxIRQ has been masked, we need not to mask it */
return 0;
}
@@ -1211,6 +849,7 @@ void *grcan_open(int dev_no)
struct grcan_priv *pDev;
void *ret;
union drvmgr_key_value *value;
+ struct grlib_canbtrs_ranges *br;
FUNCDBG();
@@ -1282,7 +921,13 @@ void *grcan_open(int dev_no)
pDev->sfilter.code = 0x00000000;
/* Calculate default timing register values */
- grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
+ if (pDev->fd_capable)
+ br = &grcanfd_nom_btrs_ranges;
+ else
+ br = &grcan_btrs_ranges;
+ grlib_canbtrs_calc_timing(
+ GRCAN_DEFAULT_BAUD, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
+ br, (struct grlib_canbtrs_timing *)&pDev->config.timing);
if ( grcan_alloc_buffers(pDev,1,1) ) {
ret = NULL;
@@ -1316,174 +961,11 @@ int grcan_close(void *d)
return 0;
}
-int grcan_read(void *d, CANMsg *msg, size_t ucount)
-{
- struct grcan_priv *pDev = d;
- CANMsg *dest;
- unsigned int count, left;
- int nread;
- int req_cnt;
-
- FUNCDBG();
-
- dest = msg;
- req_cnt = ucount;
-
- if ( (!dest) || (req_cnt<1) )
- return GRCAN_RET_INVARG;
-
- if (pDev->started != STATE_STARTED) {
- return GRCAN_RET_NOTSTARTED;
- }
-
- DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
-
- nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
- if (nread < 0) {
- return nread;
- }
- count = nread;
- if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
- if ( count > 0 ) {
- /* Successfully received messages (at least one) */
- return count;
- }
-
- /* nothing read, shall we block? */
- if ( !pDev->rxblock ) {
- /* non-blocking mode */
- return GRCAN_RET_TIMEOUT;
- }
- }
-
- while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
- if (!pDev->rxcomplete) {
- left = 1; /* return as soon as there is one message available */
- } else {
- left = req_cnt - count; /* return as soon as all data are available */
-
- /* never wait for more than the half the maximum size of the receive buffer
- * Why? We need some time to copy buffer before to catch up with hw,
- * otherwise we would have to copy everything when the data has been
- * received.
- */
- if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
- left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
- }
- }
-
- nread = grcan_wait_rxdata(pDev, left);
- if (nread) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread or a bus-off. Return error code.
- */
- return nread;
- }
-
- /* Try read bytes from circular buffer */
- nread = grcan_hw_read_try(
- pDev,
- pDev->regs,
- dest+count,
- req_cnt-count);
-
- if (nread < 0) {
- /* The read was aborted by bus-off. */
- return nread;
- }
- count += nread;
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
- return count;
-}
-
-int grcan_write(void *d, CANMsg *msg, size_t ucount)
+int grcan_canfd_capable(void *d)
{
struct grcan_priv *pDev = d;
- CANMsg *source;
- unsigned int count, left;
- int nwritten;
- int req_cnt;
-
- DBGC(DBG_TX,"\n");
-
- if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
- return GRCAN_RET_NOTSTARTED;
-
- req_cnt = ucount;
- source = (CANMsg *) msg;
-
- /* check proper length and buffer pointer */
- if (( req_cnt < 1) || (source == NULL) ){
- return GRCAN_RET_INVARG;
- }
-
- nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
- if (nwritten < 0) {
- return nwritten;
- }
- count = nwritten;
- if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
- if ( count > 0 ) {
- /* Successfully transmitted chars (at least one char) */
- return count;
- }
-
- /* nothing written, shall we block? */
- if ( !pDev->txblock ) {
- /* non-blocking mode */
- return GRCAN_RET_TIMEOUT;
- }
- }
- /* if in txcomplete mode we need to transmit all chars */
- while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
- /*** block until room to fit all or as much of transmit buffer as possible
- * IRQ comes. Set up a valid IRQ point so that an IRQ is received
- * when we can put a chunk of data into transmit fifo
- */
- if ( !pDev->txcomplete ){
- left = 1; /* wait for anything to fit buffer */
- }else{
- left = req_cnt - count; /* wait for all data to fit in buffer */
-
- /* never wait for more than the half the maximum size of the transmit
- * buffer
- * Why? We need some time to fill buffer before hw catches up.
- */
- if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
- left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
- }
- }
-
- nwritten = grcan_wait_txspace(pDev,left);
- /* Wait until more room in transmit buffer */
- if ( nwritten ) {
- /* The wait has been aborted, probably due to
- * the device driver has been closed by another
- * thread. To avoid deadlock we return directly
- * with error status.
- */
- return nwritten;
- }
-
- /* Try read bytes from circular buffer */
- nwritten = grcan_hw_write_try(
- pDev,
- pDev->regs,
- source+count,
- req_cnt-count);
-
- if (nwritten < 0) {
- /* Write was aborted by bus-off. */
- return nwritten;
- }
- count += nwritten;
- }
- /* no need to unmask IRQ as IRQ Handler do that for us. */
-
- return count;
+ return pDev->fd_capable;
}
int grcan_start(void *d)
@@ -1712,51 +1194,6 @@ int grcan_clr_stats(void *d)
return 0;
}
-int grcan_set_speed(void *d, unsigned int speed)
-{
- struct grcan_priv *pDev = d;
- struct grcan_timing timing;
- int ret;
-
- FUNCDBG();
-
- /* cannot change speed during run mode */
- if (pDev->started == STATE_STARTED)
- return -1;
-
- /* get speed rate from argument */
- ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing);
- if ( ret )
- return -2;
-
- /* save timing/speed */
- pDev->config.timing = timing;
- pDev->config_changed = 1;
-
- return 0;
-}
-
-int grcan_set_btrs(void *d, const struct grcan_timing *timing)
-{
- struct grcan_priv *pDev = d;
-
- FUNCDBG();
-
- /* Set BTR registers manually
- * Read GRCAN/HurriCANe Manual.
- */
- if (pDev->started == STATE_STARTED)
- return -1;
-
- if ( !timing )
- return -2;
-
- pDev->config.timing = *timing;
- pDev->config_changed = 1;
-
- return 0;
-}
-
int grcan_set_afilter(void *d, const struct grcan_filter *filter)
{
struct grcan_priv *pDev = d;
diff --git a/bsps/shared/grlib/can/grcan_internal.h b/bsps/shared/grlib/can/grcan_internal.h
new file mode 100644
index 0000000000..86ccda1997
--- /dev/null
+++ b/bsps/shared/grlib/can/grcan_internal.h
@@ -0,0 +1,140 @@
+/*
+ * GRCAN driver
+ *
+ * COPYRIGHT (c) 2007-2019.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef GRCAN_DEFAULT_BAUD
+ /* default to 500kbits/s */
+ #define GRCAN_DEFAULT_BAUD 500000
+#endif
+
+#ifndef GRCAN_SAMPLING_POINT
+ #define GRCAN_SAMPLING_POINT 80
+#endif
+
+#define WRAP_AROUND_TX_MSGS 1
+#define WRAP_AROUND_RX_MSGS 2
+#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
+
+struct grcan_msg {
+ unsigned int head[2];
+ unsigned char data[8];
+};
+
+struct grcan_config {
+ struct grcan_timing timing;
+ struct grcanfd_timing timing_fd;
+ struct grcan_selection selection;
+ int abort;
+ int silent;
+};
+
+struct grcan_priv {
+ struct drvmgr_dev *dev; /* Driver manager device */
+ char devName[32]; /* Device Name */
+ unsigned int baseaddr, ram_base;
+ struct grcan_regs *regs;
+ int irq;
+ int minor;
+ int open;
+ int started;
+ unsigned int channel;
+ int flushing;
+ unsigned int corefreq_hz;
+ int fd_capable;
+
+ /* Circular DMA buffers */
+ void *_rx, *_rx_hw;
+ void *_tx, *_tx_hw;
+ void *txbuf_adr;
+ void *rxbuf_adr;
+ struct grcan_msg *rx;
+ struct grcan_msg *tx;
+ unsigned int rxbuf_size; /* requested RX buf size in bytes */
+ unsigned int txbuf_size; /* requested TX buf size in bytes */
+
+ int txblock, rxblock;
+ int txcomplete, rxcomplete;
+
+ struct grcan_filter sfilter;
+ struct grcan_filter afilter;
+ int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
+ struct grcan_config config;
+ struct grcan_stats stats;
+
+ rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
+ SPIN_DECLARE(devlock);
+};
+
+#ifdef GRCAN_REG_BYPASS_CACHE
+#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
+#else
+#define READ_REG(address) (*(volatile unsigned int *)(address))
+#endif
+
+#ifdef GRCAN_DMA_BYPASS_CACHE
+#define READ_DMA_DOUBLE(address) grlib_read_uncached64((uint64_t *)(address))
+#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
+#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
+#else
+#define READ_DMA_DOUBLE(address) (*(volatile uint64_t *)(address))
+#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
+#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
+#endif
+
+extern int state2err[4];
+extern struct grlib_canbtrs_ranges grcan_btrs_ranges;
+extern struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges;
+extern struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges;
+
+int grcan_wait_rxdata(struct grcan_priv *pDev, int min);
+int grcan_wait_txspace(struct grcan_priv *pDev, int min);
+
+static inline unsigned int grcan_hw_rxavail(
+ unsigned int rp,
+ unsigned int wp,
+ unsigned int size)
+{
+ if (rp == wp) {
+ /* read pointer and write pointer is equal only
+ * when RX buffer is empty.
+ */
+ return 0;
+ }
+
+ if (wp > rp) {
+ return (wp - rp) / GRCAN_MSG_SIZE;
+ } else {
+ return (size - (rp - wp)) / GRCAN_MSG_SIZE;
+ }
+}
+
+static inline unsigned int grcan_hw_txspace(
+ unsigned int rp,
+ unsigned int wp,
+ unsigned int size)
+{
+ unsigned int left;
+
+ if (rp == wp) {
+ /* read pointer and write pointer is equal only
+ * when TX buffer is empty.
+ */
+ return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
+ }
+
+ /* size - 4 - abs(read-write) */
+ if (wp > rp) {
+ left = size - (wp - rp);
+ } else {
+ left = rp - wp;
+ }
+
+ return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
+}
diff --git a/bsps/shared/grlib/can/grcanfd.c b/bsps/shared/grlib/can/grcanfd.c
new file mode 100644
index 0000000000..00eb4b6432
--- /dev/null
+++ b/bsps/shared/grlib/can/grcanfd.c
@@ -0,0 +1,535 @@
+/*
+ * FD extenstions to the GRCAN driver
+ *
+ * COPYRIGHT (c) 2007-2019.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <grlib/grcan.h>
+#include <grlib/canbtrs.h>
+#include <drvmgr/drvmgr.h>
+#include <grlib/ambapp_bus.h>
+#include <grlib/ambapp.h>
+
+#include <grlib/grlib_impl.h>
+#include "grcan_internal.h"
+
+/* Uncomment for debug output */
+/****************** DEBUG Definitions ********************/
+#define DBG_TX 2
+#define DBG_RX 4
+#define DBG_STATE 8
+
+#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <grlib/debug_defs.h>
+
+/*********************************************************/
+
+struct grcanfd_bd0 {
+ uint32_t head[2];
+ uint64_t data0; /* variable size, from 1 to 8 dwords */
+};
+
+struct grcanfd_bd1 {
+ unsigned long long data[2];
+};
+
+static uint8_t dlc2len[16] = {
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 12, 16, 20,
+ 24, 32, 48, 64
+};
+
+static uint8_t len2fddlc[14] = {
+ /* 12,13 */ 0x9,
+ /* 16,17 */ 0xA,
+ /* 20,21 */ 0xB,
+ /* 24,25 */ 0xC,
+ /* 28,29 */ -1,
+ /* 32,33 */ 0xD,
+ /* 36,37 */ -1,
+ /* 40,41 */ -1,
+ /* 44,45 */ -1,
+ /* 48,49 */ 0xE,
+ /* 52,53 */ -1,
+ /* 56,57 */ -1,
+ /* 60,61 */ -1,
+ /* 64,65 */ 0xF,
+};
+
+/* Convert length in bytes to descriptor length field */
+static inline uint8_t grcan_len2dlc(int len)
+{
+ if (len <= 8)
+ return len;
+ if (len > 64)
+ return -1;
+ if (len & 0x3)
+ return -1;
+ return len2fddlc[(len - 12) >> 2];
+}
+
+static inline int grcan_numbds(int len)
+{
+ return 1 + ((len + 7) >> 4);
+}
+
+static int grcan_hw_read_try_fd(
+ struct grcan_priv *pDev,
+ struct grcan_regs *regs,
+ CANFDMsg * buffer,
+ int max)
+{
+ int j;
+ CANFDMsg *dest;
+ struct grcanfd_bd0 *source, tmp, *rxmax;
+ unsigned int wp, rp, size, addr;
+ int bds_hw_avail, bds_tot, bds, ret, dlc;
+ uint64_t *dp;
+ SPIN_IRQFLAGS(oldLevel);
+
+ FUNCDBG();
+
+ wp = READ_REG(&regs->rx0wr);
+ rp = READ_REG(&regs->rx0rd);
+
+ /*
+ * Due to hardware wrap around simplification write pointer will
+ * never reach the read pointer, at least a gap of 8 bytes.
+ * The only time they are equal is when the read pointer has
+ * reached the write pointer (empty buffer)
+ *
+ */
+ if (wp != rp) {
+ /* Not empty, we have received chars...
+ * Read as much as possible from DMA buffer
+ */
+ size = READ_REG(&regs->rx0size);
+
+ /* Get number of bytes available in RX buffer */
+ bds_hw_avail = grcan_hw_rxavail(rp, wp, size);
+
+ addr = (unsigned int)pDev->rx;
+ source = (struct grcanfd_bd0 *)(addr + rp);
+ dest = buffer;
+ rxmax = (struct grcanfd_bd0 *)(addr + size);
+ ret = bds_tot = 0;
+
+ /* Read as many can messages as possible */
+ while ((ret < max) && (bds_tot < bds_hw_avail)) {
+ /* Read CAN message from DMA buffer */
+ *(uint64_t *)&tmp = READ_DMA_DOUBLE(source);
+ if (tmp.head[1] & 0x4) {
+ DBGC(DBG_RX, "overrun\n");
+ }
+ if (tmp.head[1] & 0x2) {
+ DBGC(DBG_RX, "bus-off mode\n");
+ }
+ if (tmp.head[1] & 0x1) {
+ DBGC(DBG_RX, "error-passive mode\n");
+ }
+ /* Convert one grcan CAN message to one "software" CAN message */
+ dest->extended = tmp.head[0] >> 31;
+ dest->rtr = (tmp.head[0] >> 30) & 0x1;
+ if (dest->extended) {
+ dest->id = tmp.head[0] & 0x3fffffff;
+ } else {
+ dest->id = (tmp.head[0] >> 18) & 0xfff;
+ }
+ dest->fdopts = (tmp.head[1] >> 25) & GRCAN_FDMASK;
+ dlc = tmp.head[1] >> 28;
+ if (dest->fdopts & GRCAN_FDOPT_FDFRM) {
+ dest->len = dlc2len[dlc];
+ } else {
+ dest->len = dlc;
+ if (dlc > 8)
+ dest->len = 8;
+ }
+
+ dp = (uint64_t *)&source->data0;
+ for (j = 0; j < ((dest->len + 7) / 8); j++) {
+ dest->data.dwords[j] = READ_DMA_DOUBLE(dp);
+ if (++dp >= (uint64_t *)rxmax)
+ dp = (uint64_t *)addr; /* wrap around */
+ }
+
+ /* wrap around if neccessary */
+ bds = grcan_numbds(dest->len);
+ source += bds;
+ if (source >= rxmax) {
+ source = (struct grcanfd_bd0 *)
+ ((void *)source - size);
+ }
+ dest++; /* straight user buffer */
+ ret++;
+ bds_tot += bds;
+ }
+
+ /* A bus off interrupt may have occured after checking pDev->started */
+ SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+ if (pDev->started == STATE_STARTED) {
+ regs->rx0rd = (unsigned int) source - addr;
+ regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
+ } else {
+ DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+ ret = state2err[pDev->started];
+ }
+ SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+
+ return ret;
+ }
+ return 0;
+}
+
+int grcanfd_read(void *d, CANFDMsg *msg, size_t ucount)
+{
+ struct grcan_priv *pDev = d;
+ CANFDMsg *dest;
+ unsigned int count, left;
+ int nread;
+ int req_cnt;
+
+ FUNCDBG();
+
+ dest = msg;
+ req_cnt = ucount;
+
+ if ( (!dest) || (req_cnt<1) )
+ return GRCAN_RET_INVARG;
+
+ if (pDev->started != STATE_STARTED) {
+ return GRCAN_RET_NOTSTARTED;
+ }
+
+ DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
+
+ nread = grcan_hw_read_try_fd(pDev,pDev->regs,dest,req_cnt);
+ if (nread < 0) {
+ return nread;
+ }
+ count = nread;
+ if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
+ if ( count > 0 ) {
+ /* Successfully received messages (at least one) */
+ return count;
+ }
+
+ /* nothing read, shall we block? */
+ if ( !pDev->rxblock ) {
+ /* non-blocking mode */
+ return GRCAN_RET_TIMEOUT;
+ }
+ }
+
+ while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
+ if (!pDev->rxcomplete) {
+ left = 1; /* return as soon as there is one message available */
+ } else {
+ left = req_cnt - count; /* return as soon as all data are available */
+
+ /* never wait for more than the half the maximum size of the receive buffer
+ * Why? We need some time to copy buffer before to catch up with hw,
+ * otherwise we would have to copy everything when the data has been
+ * received.
+ */
+ if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
+ left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
+ }
+ }
+
+ nread = grcan_wait_rxdata(pDev, left);
+ if (nread) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread or a bus-off. Return error code.
+ */
+ return nread;
+ }
+
+ /* Try read bytes from circular buffer */
+ nread = grcan_hw_read_try_fd(
+ pDev,
+ pDev->regs,
+ dest+count,
+ req_cnt-count);
+
+ if (nread < 0) {
+ /* The read was aborted by bus-off. */
+ return nread;
+ }
+ count += nread;
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+ return count;
+}
+
+static int grcan_hw_write_try_fd(
+ struct grcan_priv *pDev,
+ struct grcan_regs *regs,
+ CANFDMsg *buffer,
+ int count)
+{
+ unsigned int rp, wp, size, addr;
+ int ret;
+ struct grcanfd_bd0 *dest, *txmax;
+ CANFDMsg *source = (CANFDMsg *) buffer;
+ int space_left;
+ unsigned int tmp;
+ int i, bds;
+ uint64_t *dp;
+ uint8_t dlc;
+ SPIN_IRQFLAGS(oldLevel);
+
+ DBGC(DBG_TX, "\n");
+
+ rp = READ_REG(&regs->tx0rd);
+ wp = READ_REG(&regs->tx0wr);
+ size = READ_REG(&regs->tx0size);
+ space_left = grcan_hw_txspace(rp, wp, size);
+
+ addr = (unsigned int)pDev->tx;
+ dest = (struct grcanfd_bd0 *)(addr + wp);
+ txmax = (struct grcanfd_bd0 *)(addr + size);
+ ret = 0;
+
+ while (source < &buffer[count]) {
+ /* Get the number of descriptors to wait for */
+ if (source->fdopts & GRCAN_FDOPT_FDFRM)
+ bds = grcan_numbds(source->len); /* next msg's buffers */
+ else
+ bds = 1;
+ if (space_left < bds)
+ break;
+
+ /* Convert and write CAN message to DMA buffer */
+ dlc = grcan_len2dlc(source->len);
+ if (dlc < 0) {
+ /* Bad user input. Report the number of written messages
+ * or an error when non sent.
+ */
+ if (ret <= 0)
+ return GRCAN_RET_INVARG;
+ break;
+ }
+ dest->head[1] = (dlc << 28) |
+ ((source->fdopts & GRCAN_FDMASK) << 25);
+ dp = &dest->data0;
+ for (i = 0; i < ((source->len + 7) / 8); i++) {
+ *dp++ = source->data.dwords[i];
+ if (dp >= (uint64_t *)txmax)
+ dp = (uint64_t *)addr; /* wrap around */
+ }
+ if (source->extended) {
+ tmp = (1 << 31) | (source->id & 0x3fffffff);
+ } else {
+ tmp = (source->id & 0xfff) << 18;
+ }
+ if (source->rtr)
+ tmp |= (1 << 30);
+ dest->head[0] = tmp;
+ source++; /* straight user buffer */
+ dest += bds;
+ if (dest >= txmax)
+ dest = (struct grcanfd_bd0 *)((void *)dest - size);
+ space_left -= bds;
+ ret++;
+ }
+
+ /* A bus off interrupt may have occured after checking pDev->started */
+ SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+ if (pDev->started == STATE_STARTED) {
+ regs->tx0wr = (unsigned int) dest - addr;
+ regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
+ } else {
+ DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+ ret = state2err[pDev->started];
+ }
+ SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+
+ return ret;
+}
+
+int grcanfd_write(
+ void *d,
+ CANFDMsg *msg,
+ size_t ucount)
+{
+ struct grcan_priv *pDev = d;
+ CANFDMsg *source, *curr;
+ unsigned int count, left;
+ int nwritten;
+ int req_cnt;
+
+ DBGC(DBG_TX,"\n");
+
+ if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
+ return GRCAN_RET_NOTSTARTED;
+
+ req_cnt = ucount;
+ curr = source = (CANFDMsg *) msg;
+
+ /* check proper length and buffer pointer */
+ if (( req_cnt < 1) || (source == NULL) ){
+ return GRCAN_RET_INVARG;
+ }
+
+ nwritten = grcan_hw_write_try_fd(pDev,pDev->regs,source,req_cnt);
+ if (nwritten < 0) {
+ return nwritten;
+ }
+ count = nwritten;
+ if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
+ if ( count > 0 ) {
+ /* Successfully transmitted chars (at least one char) */
+ return count;
+ }
+
+ /* nothing written, shall we block? */
+ if ( !pDev->txblock ) {
+ /* non-blocking mode */
+ return GRCAN_RET_TIMEOUT;
+ }
+ }
+
+ /* if in txcomplete mode we need to transmit all chars */
+ while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
+ /*** block until room to fit all or as much of transmit buffer
+ * as possible before IRQ comes. Set up a valid IRQ point so
+ * that an IRQ is triggered when we can put a chunk of data
+ * into transmit fifo.
+ */
+
+ /* Get the number of descriptors to wait for */
+ curr = &source[count];
+ if (curr->fdopts & GRCAN_FDOPT_FDFRM)
+ left = grcan_numbds(curr->len); /* next msg's buffers */
+ else
+ left = 1;
+
+ if (pDev->txcomplete) {
+ /* Wait for all messages to fit into descriptor table.
+ * Assume all following msgs are single descriptors.
+ */
+ left += req_cnt - count - 1;
+ if (left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2)) {
+ left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+
+ }
+
+ nwritten = grcan_wait_txspace(pDev,left);
+ /* Wait until more room in transmit buffer */
+ if ( nwritten ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread. To avoid deadlock we return directly
+ * with error status.
+ */
+ return nwritten;
+ }
+
+ /* Try read bytes from circular buffer */
+ nwritten = grcan_hw_write_try_fd(
+ pDev,
+ pDev->regs,
+ source+count,
+ req_cnt-count);
+
+ if (nwritten < 0) {
+ /* Write was aborted by bus-off. */
+ return nwritten;
+ }
+ count += nwritten;
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+
+ return count;
+}
+
+int grcanfd_set_speed(void *d, unsigned int nom_hz, unsigned int fd_hz)
+{
+ struct grcan_priv *pDev = d;
+ struct grlib_canbtrs_timing nom, fd;
+ int ret;
+
+ FUNCDBG();
+
+ /* cannot change speed during run mode */
+ if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
+ return -1;
+
+ /* get speed rate from argument */
+ ret = grlib_canbtrs_calc_timing(
+ nom_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
+ &grcanfd_nom_btrs_ranges, &nom);
+ if ( ret )
+ return -2;
+ ret = grlib_canbtrs_calc_timing(
+ fd_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
+ &grcanfd_fd_btrs_ranges, &fd);
+ if ( ret )
+ return -2;
+
+ /* save timing/speed */
+ pDev->config.timing = *(struct grcan_timing *)&nom;
+ pDev->config.timing_fd.scaler = fd.scaler;
+ pDev->config.timing_fd.ps1 = fd.ps1;
+ pDev->config.timing_fd.ps2 = fd.ps2;
+ pDev->config.timing_fd.sjw = fd.rsj;
+ pDev->config.timing_fd.resv_zero = 0;
+ pDev->config_changed = 1;
+
+ return 0;
+
+}
+
+int grcanfd_set_btrs(
+ void *d,
+ const struct grcanfd_timing *nominal,
+ const struct grcanfd_timing *fd)
+{
+ struct grcan_priv *pDev = d;
+
+ FUNCDBG();
+
+ /* Set BTR registers manually
+ * Read GRCAN/HurriCANe Manual.
+ */
+ if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
+ return -1;
+
+ if (!nominal)
+ return -2;
+
+ pDev->config.timing.scaler = nominal->scaler;
+ pDev->config.timing.ps1 = nominal->ps1;
+ pDev->config.timing.ps2 = nominal->ps2;
+ pDev->config.timing.rsj = nominal->sjw;
+ pDev->config.timing.bpr = 0;
+ if (fd) {
+ pDev->config.timing_fd = *fd;
+ } else {
+ memset(&pDev->config.timing_fd, 0,
+ sizeof(struct grcanfd_timing));
+ }
+ pDev->config_changed = 1;
+
+ return 0;
+}
diff --git a/bsps/shared/grlib/can/grcanstd.c b/bsps/shared/grlib/can/grcanstd.c
new file mode 100644
index 0000000000..b92c15a32b
--- /dev/null
+++ b/bsps/shared/grlib/can/grcanstd.c
@@ -0,0 +1,435 @@
+/*
+ * non-FD specific function for GRCAN driver
+ *
+ * COPYRIGHT (c) 2007-2019.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <grlib/grcan.h>
+#include <grlib/canbtrs.h>
+#include <drvmgr/drvmgr.h>
+#include <grlib/ambapp_bus.h>
+#include <grlib/ambapp.h>
+
+#include <grlib/grlib_impl.h>
+#include "grcan_internal.h"
+
+/* Uncomment for debug output */
+/****************** DEBUG Definitions ********************/
+#define DBG_TX 2
+#define DBG_RX 4
+#define DBG_STATE 8
+
+#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <grlib/debug_defs.h>
+
+static int grcan_hw_read_try(
+ struct grcan_priv *pDev,
+ struct grcan_regs *regs,
+ CANMsg * buffer,
+ int max
+)
+{
+ int i, j;
+ CANMsg *dest;
+ struct grcan_msg *source, tmp;
+ unsigned int wp, rp, size, rxmax, addr;
+ int trunk_msg_cnt;
+
+ FUNCDBG();
+
+ wp = READ_REG(&regs->rx0wr);
+ rp = READ_REG(&regs->rx0rd);
+
+ /*
+ * Due to hardware wrap around simplification write pointer will
+ * never reach the read pointer, at least a gap of 8 bytes.
+ * The only time they are equal is when the read pointer has
+ * reached the write pointer (empty buffer)
+ *
+ */
+ if (wp != rp) {
+ /* Not empty, we have received chars...
+ * Read as much as possible from DMA buffer
+ */
+ size = READ_REG(&regs->rx0size);
+
+ /* Get number of bytes available in RX buffer */
+ trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
+
+ /* truncate size if user space buffer hasn't room for
+ * all received chars.
+ */
+ if (trunk_msg_cnt > max)
+ trunk_msg_cnt = max;
+
+ /* Read until i is 0 */
+ i = trunk_msg_cnt;
+
+ addr = (unsigned int)pDev->rx;
+ source = (struct grcan_msg *)(addr + rp);
+ dest = buffer;
+ rxmax = addr + (size - GRCAN_MSG_SIZE);
+
+ /* Read as many can messages as possible */
+ while (i > 0) {
+ /* Read CAN message from DMA buffer */
+ tmp.head[0] = READ_DMA_WORD(&source->head[0]);
+ tmp.head[1] = READ_DMA_WORD(&source->head[1]);
+ if (tmp.head[1] & 0x4) {
+ DBGC(DBG_RX, "overrun\n");
+ }
+ if (tmp.head[1] & 0x2) {
+ DBGC(DBG_RX, "bus-off mode\n");
+ }
+ if (tmp.head[1] & 0x1) {
+ DBGC(DBG_RX, "error-passive mode\n");
+ }
+ /* Convert one grcan CAN message to one "software" CAN message */
+ dest->extended = tmp.head[0] >> 31;
+ dest->rtr = (tmp.head[0] >> 30) & 0x1;
+ if (dest->extended) {
+ dest->id = tmp.head[0] & 0x3fffffff;
+ } else {
+ dest->id = (tmp.head[0] >> 18) & 0xfff;
+ }
+ dest->len = tmp.head[1] >> 28;
+ for (j = 0; j < dest->len; j++)
+ dest->data[j] = READ_DMA_BYTE(&source->data[j]);
+
+ /* wrap around if neccessary */
+ source =
+ ((unsigned int)source >= rxmax) ?
+ (struct grcan_msg *)addr : source + 1;
+ dest++; /* straight user buffer */
+ i--;
+ }
+ {
+ /* A bus off interrupt may have occured after checking pDev->started */
+ SPIN_IRQFLAGS(oldLevel);
+
+ SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+ if (pDev->started == STATE_STARTED) {
+ regs->rx0rd = (unsigned int) source - addr;
+ regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
+ } else {
+ DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+ trunk_msg_cnt = state2err[pDev->started];
+ }
+ SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+ }
+ return trunk_msg_cnt;
+ }
+ return 0;
+}
+
+static int grcan_hw_write_try(
+ struct grcan_priv *pDev,
+ struct grcan_regs *regs,
+ CANMsg * buffer,
+ int count
+)
+{
+ unsigned int rp, wp, size, txmax, addr;
+ int ret;
+ struct grcan_msg *dest;
+ CANMsg *source;
+ int space_left;
+ unsigned int tmp;
+ int i;
+
+ DBGC(DBG_TX, "\n");
+ /*FUNCDBG(); */
+
+ rp = READ_REG(&regs->tx0rd);
+ wp = READ_REG(&regs->tx0wr);
+ size = READ_REG(&regs->tx0size);
+
+ space_left = grcan_hw_txspace(rp, wp, size);
+
+ /* is circular fifo full? */
+ if (space_left < 1)
+ return 0;
+
+ /* Truncate size */
+ if (space_left > count)
+ space_left = count;
+ ret = space_left;
+
+ addr = (unsigned int)pDev->tx;
+
+ dest = (struct grcan_msg *)(addr + wp);
+ source = (CANMsg *) buffer;
+ txmax = addr + (size - GRCAN_MSG_SIZE);
+
+ while (space_left > 0) {
+ /* Convert and write CAN message to DMA buffer */
+ if (source->extended) {
+ tmp = (1 << 31) | (source->id & 0x3fffffff);
+ } else {
+ tmp = (source->id & 0xfff) << 18;
+ }
+ if (source->rtr)
+ tmp |= (1 << 30);
+ dest->head[0] = tmp;
+ dest->head[1] = source->len << 28;
+ for (i = 0; i < source->len; i++)
+ dest->data[i] = source->data[i];
+ source++; /* straight user buffer */
+ dest =
+ ((unsigned int)dest >= txmax) ?
+ (struct grcan_msg *)addr : dest + 1;
+ space_left--;
+ }
+
+ {
+ /* A bus off interrupt may have occured after checking pDev->started */
+ SPIN_IRQFLAGS(oldLevel);
+
+ SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
+ if (pDev->started == STATE_STARTED) {
+ regs->tx0wr = (unsigned int) dest - addr;
+ regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
+ } else {
+ DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
+ ret = state2err[pDev->started];
+ }
+ SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+ }
+ return ret;
+}
+
+
+int grcan_read(void *d, CANMsg *msg, size_t ucount)
+{
+ struct grcan_priv *pDev = d;
+ CANMsg *dest;
+ unsigned int count, left;
+ int nread;
+ int req_cnt;
+
+ FUNCDBG();
+
+ dest = msg;
+ req_cnt = ucount;
+
+ if ( (!dest) || (req_cnt<1) )
+ return GRCAN_RET_INVARG;
+
+ if (pDev->started != STATE_STARTED) {
+ return GRCAN_RET_NOTSTARTED;
+ }
+
+ DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
+
+ nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
+ if (nread < 0) {
+ return nread;
+ }
+ count = nread;
+ if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
+ if ( count > 0 ) {
+ /* Successfully received messages (at least one) */
+ return count;
+ }
+
+ /* nothing read, shall we block? */
+ if ( !pDev->rxblock ) {
+ /* non-blocking mode */
+ return GRCAN_RET_TIMEOUT;
+ }
+ }
+
+ while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
+ if (!pDev->rxcomplete) {
+ left = 1; /* return as soon as there is one message available */
+ } else {
+ left = req_cnt - count; /* return as soon as all data are available */
+
+ /* never wait for more than the half the maximum size of the receive buffer
+ * Why? We need some time to copy buffer before to catch up with hw,
+ * otherwise we would have to copy everything when the data has been
+ * received.
+ */
+ if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
+ left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
+ }
+ }
+
+ nread = grcan_wait_rxdata(pDev, left);
+ if (nread) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread or a bus-off. Return error code.
+ */
+ return nread;
+ }
+
+ /* Try read bytes from circular buffer */
+ nread = grcan_hw_read_try(
+ pDev,
+ pDev->regs,
+ dest+count,
+ req_cnt-count);
+
+ if (nread < 0) {
+ /* The read was aborted by bus-off. */
+ return nread;
+ }
+ count += nread;
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+ return count;
+}
+
+int grcan_write(void *d, CANMsg *msg, size_t ucount)
+{
+ struct grcan_priv *pDev = d;
+ CANMsg *source;
+ unsigned int count, left;
+ int nwritten;
+ int req_cnt;
+
+ DBGC(DBG_TX,"\n");
+
+ if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
+ return GRCAN_RET_NOTSTARTED;
+
+ req_cnt = ucount;
+ source = (CANMsg *) msg;
+
+ /* check proper length and buffer pointer */
+ if (( req_cnt < 1) || (source == NULL) ){
+ return GRCAN_RET_INVARG;
+ }
+
+ nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
+ if (nwritten < 0) {
+ return nwritten;
+ }
+ count = nwritten;
+ if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
+ if ( count > 0 ) {
+ /* Successfully transmitted chars (at least one char) */
+ return count;
+ }
+
+ /* nothing written, shall we block? */
+ if ( !pDev->txblock ) {
+ /* non-blocking mode */
+ return GRCAN_RET_TIMEOUT;
+ }
+ }
+
+ /* if in txcomplete mode we need to transmit all chars */
+ while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
+ /*** block until room to fit all or as much of transmit buffer as possible
+ * IRQ comes. Set up a valid IRQ point so that an IRQ is received
+ * when we can put a chunk of data into transmit fifo
+ */
+ if ( !pDev->txcomplete ){
+ left = 1; /* wait for anything to fit buffer */
+ }else{
+ left = req_cnt - count; /* wait for all data to fit in buffer */
+
+ /* never wait for more than the half the maximum size of the transmit
+ * buffer
+ * Why? We need some time to fill buffer before hw catches up.
+ */
+ if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
+ left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
+ }
+ }
+
+ nwritten = grcan_wait_txspace(pDev,left);
+ /* Wait until more room in transmit buffer */
+ if ( nwritten ) {
+ /* The wait has been aborted, probably due to
+ * the device driver has been closed by another
+ * thread. To avoid deadlock we return directly
+ * with error status.
+ */
+ return nwritten;
+ }
+
+ /* Try read bytes from circular buffer */
+ nwritten = grcan_hw_write_try(
+ pDev,
+ pDev->regs,
+ source+count,
+ req_cnt-count);
+
+ if (nwritten < 0) {
+ /* Write was aborted by bus-off. */
+ return nwritten;
+ }
+ count += nwritten;
+ }
+ /* no need to unmask IRQ as IRQ Handler do that for us. */
+
+ return count;
+}
+
+
+int grcan_set_speed(void *d, unsigned int speed)
+{
+ struct grcan_priv *pDev = d;
+ struct grcan_timing timing;
+ int ret;
+
+ FUNCDBG();
+
+ /* cannot change speed during run mode */
+ if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
+ return -1;
+
+ /* get speed rate from argument */
+ ret = grlib_canbtrs_calc_timing(
+ speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
+ &grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
+ if (ret)
+ return -2;
+
+ /* save timing/speed */
+ pDev->config.timing = timing;
+ pDev->config_changed = 1;
+
+ return 0;
+}
+
+int grcan_set_btrs(void *d, const struct grcan_timing *timing)
+{
+ struct grcan_priv *pDev = d;
+
+ FUNCDBG();
+
+ /* Set BTR registers manually
+ * Read GRCAN/HurriCANe Manual.
+ */
+ if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
+ return -1;
+
+ if ( !timing )
+ return -2;
+
+ pDev->config.timing = *timing;
+ pDev->config_changed = 1;
+
+ return 0;
+}
diff --git a/bsps/shared/grlib/can/occan.c b/bsps/shared/grlib/can/occan.c
index 59b4f234f6..01537f9390 100644
--- a/bsps/shared/grlib/can/occan.c
+++ b/bsps/shared/grlib/can/occan.c
@@ -19,6 +19,7 @@
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/occan.h>
+#include <grlib/canbtrs.h>
#include <grlib/grlib_impl.h>
@@ -185,19 +186,20 @@ typedef struct {
#define pelican_regs pelican32_regs
#endif
+/* Default sampling point in % */
+#define OCCAN_SAMPLING_POINT 90
+
+/* OCCAN baud-rate paramter boundaries */
+struct grlib_canbtrs_ranges occan_btrs_ranges = {
+ .max_scaler = 64,
+ .has_bpr = 0,
+ .divfactor = 1,
+ .min_tseg1 = 1,
+ .max_tseg1 = 16,
+ .min_tseg2 = 1,
+ .max_tseg2 = 8,
+};
-#define MAX_TSEG2 7
-#define MAX_TSEG1 15
-
-#if 0
-typedef struct {
- unsigned char brp;
- unsigned char sjw;
- unsigned char tseg1;
- unsigned char tseg2;
- unsigned char sam;
-} occan_speed_regs;
-#endif
typedef struct {
unsigned char btr0;
unsigned char btr1;
@@ -251,7 +253,9 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
static void occan_fifo_clr(occan_fifo *fifo);
/**** Hardware related Interface ****/
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
+static void convert_timing_to_btrs(
+ struct grlib_canbtrs_timing *t,
+ occan_speed_regs *btrs);
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
static void pelican_init(occan_priv *priv);
static void pelican_open(occan_priv *priv);
@@ -765,6 +769,7 @@ static void pelican_init(occan_priv *priv){
static void pelican_open(occan_priv *priv){
int ret;
+ struct grlib_canbtrs_timing timing;
/* Set defaults */
priv->speed = OCCAN_SPEED_250K;
@@ -783,13 +788,19 @@ static void pelican_open(occan_priv *priv){
*/
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
- ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
- if ( ret ){
+ ret = grlib_canbtrs_calc_timing(
+ priv->speed, priv->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
+ if ( ret ) {
/* failed to set speed for this system freq, try with 50K instead */
priv->speed = OCCAN_SPEED_50K;
- occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
- &priv->timing);
+ grlib_canbtrs_calc_timing(
+ priv->speed, priv->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
}
+ convert_timing_to_btrs(&timing, &priv->timing);
/* disable all interrupts */
WRITE_REG(priv, &priv->regs->inten, 0);
@@ -983,97 +994,13 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
WRITE_REG(priv, amask3, amask[3]);
}
-
-/* This function calculates BTR0 and BTR1 values for a given bitrate.
- *
- * Set communication parameters.
- * \param clock_hz OC_CAN Core frequency in Hz.
- * \param rate Requested baud rate in bits/second.
- * \param result Pointer to where resulting BTRs will be stored.
- * \return zero if successful to calculate a baud rate.
- */
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
+static void convert_timing_to_btrs(
+ struct grlib_canbtrs_timing *t,
+ occan_speed_regs *btrs)
{
- int best_error = 1000000000;
- int error;
- int best_tseg=0, best_brp=0, brp=0;
- int tseg=0, tseg1=0, tseg2=0;
- int sjw = 0;
- int clock = clock_hz / 2;
- int sampl_pt = 90;
-
- if ( (rate<5000) || (rate>1000000) ){
- /* invalid speed mode */
- return -1;
- }
-
- /* find best match, return -2 if no good reg
- * combination is available for this frequency */
-
- /* some heuristic specials */
- if (rate > ((1000000 + 500000) / 2))
- sampl_pt = 75;
-
- if (rate < ((12500 + 10000) / 2))
- sampl_pt = 75;
-
- if (rate < ((100000 + 125000) / 2))
- sjw = 1;
-
- /* tseg even = round down, odd = round up */
- for (tseg = (0 + 0 + 2) * 2;
- tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
- tseg++)
- {
- brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
- if ((brp == 0) || (brp > 64))
- continue;
-
- error = rate - clock / (brp * (1 + tseg / 2));
- if (error < 0)
- {
- error = -error;
- }
-
- if (error <= best_error)
- {
- best_error = error;
- best_tseg = tseg/2;
- best_brp = brp-1;
- }
- }
-
- if (best_error && (rate / best_error < 10))
- {
- printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
- return -2;
- }else if ( !result )
- return 0; /* nothing to store result in, but a valid bitrate can be calculated */
-
- tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
-
- if (tseg2 < 0)
- {
- tseg2 = 0;
- }
-
- if (tseg2 > MAX_TSEG2)
- {
- tseg2 = MAX_TSEG2;
- }
-
- tseg1 = best_tseg - tseg2 - 2;
-
- if (tseg1 > MAX_TSEG1)
- {
- tseg1 = MAX_TSEG1;
- tseg2 = best_tseg - tseg1 - 2;
- }
-
- result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
- result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
-
- return 0;
+ btrs->btr0 = (t->rsj << OCCAN_BUSTIM_SJW_BIT) |
+ (t->scaler & OCCAN_BUSTIM_BRP);
+ btrs->btr1 = (0<<7) | (t->ps2 << OCCAN_BUSTIM_TSEG2_BIT) | t->ps1;
}
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
@@ -1441,7 +1368,7 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
int ret;
- occan_speed_regs timing;
+ struct grlib_canbtrs_timing timing;
occan_priv *can;
struct drvmgr_dev *dev;
unsigned int speed;
@@ -1467,7 +1394,11 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
- ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
+ /* Calculate default timing register values */
+ ret = grlib_canbtrs_calc_timing(
+ speed, can->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1476,7 +1407,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* save timing/speed */
can->speed = speed;
- can->timing = timing;
+ convert_timing_to_btrs(&timing, &can->timing);
break;
case OCCAN_IOC_SET_BTRS:
diff --git a/bsps/shared/grlib/irq/genirq.c b/bsps/shared/grlib/irq/genirq.c
index 285416b0d3..ca80445c70 100644
--- a/bsps/shared/grlib/irq/genirq.c
+++ b/bsps/shared/grlib/irq/genirq.c
@@ -188,8 +188,8 @@ static int genirq_set_active(
return 1;
}
e = isrentry;
- } else {
- enabled += isrentry->enabled;
+ } else if ( isrentry->enabled ) {
+ enabled = 1;
}
isrentry = isrentry->next;
}
diff --git a/bsps/shared/grlib/l2c/l2c.c b/bsps/shared/grlib/l2c/l2c.c
index ddef0ada5c..4a443ed7cf 100644
--- a/bsps/shared/grlib/l2c/l2c.c
+++ b/bsps/shared/grlib/l2c/l2c.c
@@ -894,9 +894,9 @@ int l2cache_diag_tag( int way, int index, struct l2cache_tag * tag)
return L2CACHE_ERR_EINVAL;
}
- unsigned int val = l2cache_reg_diagtag(way,index);
-
if (tag){
+ unsigned int val = l2cache_reg_diagtag(way,index);
+
tag->tag = l2cache_get_tag(val);
tag->valid = l2cache_tag_valid(val);
tag->dirty = l2cache_tag_dirty(val);
diff --git a/bsps/shared/grlib/net/greth.c b/bsps/shared/grlib/net/greth.c
index bc4d3cc40f..09cfb325ba 100644
--- a/bsps/shared/grlib/net/greth.c
+++ b/bsps/shared/grlib/net/greth.c
@@ -186,6 +186,7 @@ struct greth_softc
unsigned int advmodes; /* advertise ethernet speed modes. 0 = all modes. */
struct timespec auto_neg_time;
int mc_available;
+ int num_descs;
/*
* Statistics
@@ -422,7 +423,7 @@ greth_initialize_hardware (struct greth_softc *sc)
int tmp2;
struct timespec tstart, tnow;
greth_regs *regs;
- unsigned int advmodes, speed;
+ unsigned int advmodes, speed, tabsize;
regs = sc->regs;
@@ -616,8 +617,9 @@ auto_neg_done:
/* Initialize rx/tx descriptor table pointers. Due to alignment we
* always allocate maximum table size.
*/
- sc->txdesc = (greth_rxtxdesc *) almalloc(0x800, 0x400);
- sc->rxdesc = (greth_rxtxdesc *) &sc->txdesc[128];
+ tabsize = sc->num_descs * 8;
+ sc->txdesc = (greth_rxtxdesc *) almalloc(tabsize * 2, tabsize);
+ sc->rxdesc = (greth_rxtxdesc *) (tabsize + (void *)sc->txdesc);
sc->tx_ptr = 0;
sc->tx_dptr = 0;
sc->tx_cnt = 0;
@@ -631,8 +633,8 @@ auto_neg_done:
CPUMEM_TO_DMA,
(void *)sc->txdesc,
(void **)&sc->txdesc_remote,
- 0x800);
- sc->rxdesc_remote = sc->txdesc_remote + 0x400;
+ tabsize * 2);
+ sc->rxdesc_remote = sc->txdesc_remote + tabsize;
regs->txdesc = (int) sc->txdesc_remote;
regs->rxdesc = (int) sc->rxdesc_remote;
@@ -1555,6 +1557,7 @@ int greth_device_init(struct greth_softc *sc)
struct ambapp_core *pnpinfo;
union drvmgr_key_value *value;
unsigned int speed;
+ int i, nrd;
/* Get device information from AMBA PnP information */
ambadev = (struct amba_dev_info *)sc->dev->businfo;
@@ -1608,12 +1611,17 @@ int greth_device_init(struct greth_softc *sc)
sc->rxbufs = 32;
sc->phyaddr = -1;
+ /* Probe the number of descriptors available the */
+ nrd = (sc->regs->status & GRETH_STATUS_NRD) >> 24;
+ for (sc->num_descs = 128, i = 0; i < nrd; i++)
+ sc->num_descs = sc->num_descs * 2;
+
value = drvmgr_dev_key_get(sc->dev, "txDescs", DRVMGR_KT_INT);
- if ( value && (value->i <= 128) )
+ if ( value && (value->i <= sc->num_descs) )
sc->txbufs = value->i;
value = drvmgr_dev_key_get(sc->dev, "rxDescs", DRVMGR_KT_INT);
- if ( value && (value->i <= 128) )
+ if ( value && (value->i <= sc->num_descs) )
sc->rxbufs = value->i;
value = drvmgr_dev_key_get(sc->dev, "phyAdr", DRVMGR_KT_INT);
diff --git a/bsps/shared/grlib/spw/grspw.c b/bsps/shared/grlib/spw/grspw.c
index 2e1e8e90e9..dd61b7a472 100644
--- a/bsps/shared/grlib/spw/grspw.c
+++ b/bsps/shared/grlib/spw/grspw.c
@@ -261,6 +261,7 @@ static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
static void grspw_rxnext(GRSPW_DEV *pDev);
static void grspw_interrupt(void *arg);
static int grspw_buffer_alloc(GRSPW_DEV *pDev);
+static int grspw_dmatables_alloc(GRSPW_DEV *pDev);
static rtems_device_driver grspw_initialize(
rtems_device_major_number major,
@@ -553,6 +554,8 @@ int grspw_device_init(GRSPW_DEV *pDev)
if (grspw_buffer_alloc(pDev))
return RTEMS_NO_MEMORY;
+ if (grspw_dmatables_alloc(pDev))
+ return RTEMS_NO_MEMORY;
/* Create semaphores */
rtems_semaphore_create(
@@ -678,7 +681,11 @@ static int grspw_buffer_alloc(GRSPW_DEV *pDev)
(void **)&pDev->ptr_txhbuf0_remote,
pDev->txhbufsize * pDev->txbufcnt);
}
+ return 0;
+}
+static int grspw_dmatables_alloc(GRSPW_DEV *pDev)
+{
/* DMA DESCRIPTOR TABLES */
if (pDev->bd_dma_area & 1) {
/* Address given in remote address */
diff --git a/bsps/shared/grlib/spw/grspw_router.c b/bsps/shared/grlib/spw/grspw_router.c
index d8ba8feef3..9a31c3b49a 100644
--- a/bsps/shared/grlib/spw/grspw_router.c
+++ b/bsps/shared/grlib/spw/grspw_router.c
@@ -1431,6 +1431,11 @@ int router_port_link_start(void *d, int port)
return router_port_ctrl_rmw(d, port, NULL, PCTRL_LD | PCTRL_LS, PCTRL_LS);
}
+int router_port_link_div(void *d, int port, int rundiv)
+{
+ return router_port_ctrl_rmw(d, port, NULL, PCTRL_RD, (rundiv << PCTRL_RD_BIT) & PCTRL_RD);
+}
+
int router_port_link_receive_spill(void *d, int port)
{
struct router_priv *priv = d;
diff --git a/bsps/shared/irq/irq-default-handler.c b/bsps/shared/irq/irq-default-handler.c
index 4f4b4be673..cfe91f4202 100644
--- a/bsps/shared/irq/irq-default-handler.c
+++ b/bsps/shared/irq/irq-default-handler.c
@@ -1,15 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup bsp_interrupt
+ *
+ * @brief This source file contains the default implementation of
+ * bsp_interrupt_handler_default().
+ */
+
/*
- * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
+ * Copyright (C) 2008, 2012 embedded brains GmbH (http://www.embedded-brains.de)
*
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
diff --git a/bsps/shared/irq/irq-default.c b/bsps/shared/irq/irq-default.c
index 9295f1fb44..943b4ea191 100644
--- a/bsps/shared/irq/irq-default.c
+++ b/bsps/shared/irq/irq-default.c
@@ -1,13 +1,17 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
- * @ingroup RTEMSBSPsShared
+ * @ingroup bsp_interrupt
+ *
+ * @brief This source file contains the default implementation of
+ * bsp_interrupt_vector_enable(), bsp_interrupt_vector_disable(), and
+ * bsp_interrupt_facility_initialize().
*/
/*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (C) 2019 embedded brains GmbH
+ * Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/bsps/shared/irq/irq-generic.c b/bsps/shared/irq/irq-generic.c
index fd129333ba..1e83a6f249 100644
--- a/bsps/shared/irq/irq-generic.c
+++ b/bsps/shared/irq/irq-generic.c
@@ -1,25 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt support implementation.
+ * @brief This source file contains the generic interrupt controller support
+ * implementation.
*/
/*
- * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
- *
- * Copyright (c) 2008, 2018 embedded brains GmbH.
+ * Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
*
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp/irq-generic.h>
diff --git a/bsps/shared/irq/irq-info.c b/bsps/shared/irq/irq-info.c
index ef965d3d07..b1df3b2915 100644
--- a/bsps/shared/irq/irq-info.c
+++ b/bsps/shared/irq/irq-info.c
@@ -1,22 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt information implementation.
+ * @brief This source file contains the implementation of
+ * bsp_interrupt_report() and bsp_interrupt_report_with_plugin().
*/
/*
- * Copyright (c) 2008, 2009, 2010
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2008, 2010 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
diff --git a/bsps/shared/irq/irq-legacy.c b/bsps/shared/irq/irq-legacy.c
index 64c324b472..649b850095 100644
--- a/bsps/shared/irq/irq-legacy.c
+++ b/bsps/shared/irq/irq-legacy.c
@@ -1,22 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt support legacy implementation.
+ * @brief This source file contains the legacy interrupt controller support
+ * implementation.
*/
/*
- * Copyright (c) 2008, 2009
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
diff --git a/bsps/shared/irq/irq-lock.c b/bsps/shared/irq/irq-lock.c
index 1398aff3eb..58b7020a3b 100644
--- a/bsps/shared/irq/irq-lock.c
+++ b/bsps/shared/irq/irq-lock.c
@@ -1,25 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief BSP interrupt support lock implementation.
+ * @brief This source file contains the implementation of
+ * bsp_interrupt_lock() and bsp_interrupt_unlock().
*/
/*
- * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
- *
- * Copyright (c) 2008, 2018 embedded brains GmbH.
+ * Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
*
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp/irq-generic.h>
diff --git a/bsps/shared/irq/irq-server.c b/bsps/shared/irq/irq-server.c
index 2c8df4952c..fa2153fcb0 100644
--- a/bsps/shared/irq/irq-server.c
+++ b/bsps/shared/irq/irq-server.c
@@ -1,17 +1,36 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt server implementation.
+ * @brief This source file contains the interrupt server implementation.
*/
/*
* Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
diff --git a/bsps/shared/irq/irq-shell.c b/bsps/shared/irq/irq-shell.c
index ca936f8038..cf70f2ce1b 100644
--- a/bsps/shared/irq/irq-shell.c
+++ b/bsps/shared/irq/irq-shell.c
@@ -1,22 +1,37 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
/**
* @file
*
* @ingroup bsp_interrupt
*
- * @brief Generic BSP interrupt shell implementation.
+ * @brief This source file contains the definition of
+ * ::bsp_interrupt_shell_command.
*/
/*
- * Copyright (c) 2009
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2009 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
diff --git a/bsps/sparc/leon3/start/amba.c b/bsps/sparc/leon3/start/amba.c
index e7ff29808c..1de206139f 100644
--- a/bsps/sparc/leon3/start/amba.c
+++ b/bsps/sparc/leon3/start/amba.c
@@ -34,18 +34,6 @@ struct ambapp_bus ambapp_plb;
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus_grlib.h>
-extern void gptimer_register_drv (void);
-extern void apbuart_cons_register_drv(void);
-/* All drivers included by BSP, this is overridden by the user by including
- * the drvmgr_confdefs.h. By default the Timer and UART driver are included.
- */
-drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
-{
- gptimer_register_drv,
- apbuart_cons_register_drv,
- NULL /* End array with NULL */
-};
-
/* Driver resources configuration for AMBA root bus. It is declared weak
* so that the user may override it, if the defualt settings are not
* enough.
diff --git a/bsps/sparc/leon3/start/cpucounter.c b/bsps/sparc/leon3/start/cpucounter.c
index 007bb6d8ec..4a0a5fe116 100644
--- a/bsps/sparc/leon3/start/cpucounter.c
+++ b/bsps/sparc/leon3/start/cpucounter.c
@@ -60,7 +60,10 @@ static void leon3_counter_initialize(void)
counter->counter_register = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].value;
/* Enable timer just in case no clock driver is configured */
- gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN;
+ gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].reload = 0xffffffff;
+ gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN |
+ GPTIMER_TIMER_CTRL_RS |
+ GPTIMER_TIMER_CTRL_LD;
leon3_counter_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev) /
(gpt->scaler_reload + 1);
diff --git a/bsps/sparc/leon3/start/drvmgr_def_drivers.c b/bsps/sparc/leon3/start/drvmgr_def_drivers.c
new file mode 100644
index 0000000000..688b37bab9
--- /dev/null
+++ b/bsps/sparc/leon3/start/drvmgr_def_drivers.c
@@ -0,0 +1,28 @@
+/*
+ * Default BSP drivers when Driver Manager enabled
+ *
+ * COPYRIGHT (c) 2019.
+ * Cobham Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+#include <bsp.h>
+
+#ifdef RTEMS_DRVMGR_STARTUP
+#include <drvmgr/drvmgr.h>
+
+extern void gptimer_register_drv (void);
+extern void apbuart_cons_register_drv(void);
+/* All drivers included by BSP, this is overridden by the user by including
+ * the drvmgr_confdefs.h. By default the Timer and UART driver are included.
+ */
+drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
+{
+ gptimer_register_drv,
+ apbuart_cons_register_drv,
+ NULL /* End array with NULL */
+};
+
+#endif
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
index cfd59475c2..449053b831 100644
--- a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
@@ -71,6 +71,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-a9mpcore.
# I2C
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/xilinx-zynq/i2c/cadence-i2c.c
+# SPI
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
+
# Cache
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-l2c-310.c
diff --git a/c/src/lib/libbsp/arm/xilinx-zynqmp/Makefile.am b/c/src/lib/libbsp/arm/xilinx-zynqmp/Makefile.am
index 0b49990ce7..6686ca4e04 100644
--- a/c/src/lib/libbsp/arm/xilinx-zynqmp/Makefile.am
+++ b/c/src/lib/libbsp/arm/xilinx-zynqmp/Makefile.am
@@ -66,6 +66,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/serial/zynq-uart-poll
# Clock
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-generic-timer.c
+# SPI
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
+
# Cache
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
index caa4abbb78..83abcdee18 100644
--- a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am
@@ -92,9 +92,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/btimer/btimer-ppc
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/bat.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/mmuAsm.S
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/pte121.c
-librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-generic.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-default-handler.c
-include $(srcdir)/../../../../../../bsps/shared/irq-default-sources.am
+include $(srcdir)/../../../../../../bsps/shared/irq-sources.am
include $(srcdir)/../../../../../../bsps/shared/shared-sources.am
include $(top_srcdir)/../../../../automake/subdirs.am
include $(srcdir)/../../../../../../bsps/powerpc/shared/shared-sources.am
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index 7933a48024..beb1b96767 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -38,6 +38,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspreset-empty.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/cpucounter.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/shared/start/bsp_fatal_exit.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/bsp_fatal_halt.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/drvmgr_def_drivers.c
# gnatsupp
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/gnatsupp/gnatsupp.c
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 51f38c84c7..202cf3c346 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -930,6 +930,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c
librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c
librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c
librtemscpu_a_SOURCES += score/src/stackallocator.c
+librtemscpu_a_SOURCES += score/src/stackallocatorforidle.c
librtemscpu_a_SOURCES += score/src/pheapallocate.c
librtemscpu_a_SOURCES += score/src/pheapextend.c
librtemscpu_a_SOURCES += score/src/pheapfree.c
@@ -1483,6 +1484,10 @@ librtemscpu_a_SOURCES += libmisc/shell/login_prompt.c
librtemscpu_a_SOURCES += libmisc/shell/login_check.c
librtemscpu_a_SOURCES += libmisc/shell/fdisk.c
librtemscpu_a_SOURCES += libmisc/shell/main_rtc.c
+librtemscpu_a_SOURCES += libmisc/shell/main_spi.c
+librtemscpu_a_SOURCES += libmisc/shell/main_i2cdetect.c
+librtemscpu_a_SOURCES += libmisc/shell/main_i2cset.c
+librtemscpu_a_SOURCES += libmisc/shell/main_i2cget.c
librtemscpu_a_SOURCES += libmisc/shell/dd-args.c
librtemscpu_a_SOURCES += libmisc/shell/main_dd.c
librtemscpu_a_SOURCES += libmisc/shell/dd-conv.c
diff --git a/cpukit/headers.am b/cpukit/headers.am
index fcf679f09d..6bd0535a74 100644
--- a/cpukit/headers.am
+++ b/cpukit/headers.am
@@ -416,6 +416,7 @@ include_rtems_score_HEADERS += include/rtems/score/threadimpl.h
include_rtems_score_HEADERS += include/rtems/score/threadmp.h
include_rtems_score_HEADERS += include/rtems/score/threadq.h
include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h
+include_rtems_score_HEADERS += include/rtems/score/threadqops.h
include_rtems_score_HEADERS += include/rtems/score/timecounter.h
include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h
include_rtems_score_HEADERS += include/rtems/score/timespec.h
diff --git a/cpukit/include/link_elf.h b/cpukit/include/link_elf.h
index 6cab3c2c7f..6483c021fd 100644
--- a/cpukit/include/link_elf.h
+++ b/cpukit/include/link_elf.h
@@ -13,6 +13,10 @@
#include <stdint.h>
#include <rtems/rtl/rtl-obj-fwd.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum sections
{
rap_text = 0,
@@ -76,4 +80,8 @@ int _rtld_linkmap_add (rtems_rtl_obj* obj);
* Remove link map from the list.
*/
void _rtld_linkmap_delete (rtems_rtl_obj* obj);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* _LINK_ELF_H_ */
diff --git a/cpukit/include/linux/rbtree.h b/cpukit/include/linux/rbtree.h
index 8fc575240f..ec0fac1af9 100644
--- a/cpukit/include/linux/rbtree.h
+++ b/cpukit/include/linux/rbtree.h
@@ -17,6 +17,10 @@
#include <rtems/score/rbtree.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define rb_node RBTree_Node
#define rb_left Node.rbe_left
@@ -96,7 +100,7 @@ static inline struct rb_node *rb_last( struct rb_root *root )
static inline void rb_replace_node(
struct rb_node *victim,
- struct rb_node *replacement,
+ struct rb_node *replacement,
struct rb_root *root
)
{
@@ -138,4 +142,8 @@ static inline struct rb_node *rb_parent( struct rb_node *node )
node = next \
)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _LINUX_RBTREE_H */
diff --git a/cpukit/include/rtems/capture.h b/cpukit/include/rtems/capture.h
index c37d652211..4ab638ec24 100644
--- a/cpukit/include/rtems/capture.h
+++ b/cpukit/include/rtems/capture.h
@@ -838,7 +838,7 @@ rtems_capture_task_flags (rtems_tcb* tcb)
static inline rtems_capture_control*
rtems_capture_task_control (rtems_tcb* tcb)
{
- return tcb->Capture.control;
+ return (rtems_capture_control*) tcb->Capture.control;
}
/**
@@ -853,7 +853,7 @@ rtems_capture_task_control (rtems_tcb* tcb)
static inline uint32_t
rtems_capture_task_control_flags (rtems_tcb* tcb)
{
- rtems_capture_control* control = tcb->Capture.control;
+ rtems_capture_control* control = rtems_capture_task_control (tcb);
if (!control)
return 0;
return control->flags;
diff --git a/cpukit/include/rtems/confdefs/percpu.h b/cpukit/include/rtems/confdefs/percpu.h
index f3a9a4f3e7..b7baebea05 100644
--- a/cpukit/include/rtems/confdefs/percpu.h
+++ b/cpukit/include/rtems/confdefs/percpu.h
@@ -133,11 +133,19 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
-char _Thread_Idle_stacks[
- _CONFIGURE_MAXIMUM_PROCESSORS
- * ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
-] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
-RTEMS_SECTION( ".rtemsstack.idle" );
+/*
+ * If the user provides a custom idle stack allocator, then we do not need
+ * memory reserved for the stacks but the symbol is still referenced in
+ * threadcreateidle.c. The code path just never uses it. Make it minimal
+ * size to proceed.
+ */
+#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ char _Thread_Idle_stacks[
+ _CONFIGURE_MAXIMUM_PROCESSORS
+ * ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
+ ] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
+ RTEMS_SECTION( ".rtemsstack.idle" );
+#endif
#if defined(CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION) && \
!defined(CONFIGURE_IDLE_TASK_BODY)
diff --git a/cpukit/include/rtems/confdefs/wkspace.h b/cpukit/include/rtems/confdefs/wkspace.h
index 484dde20ea..9ef9d90b85 100644
--- a/cpukit/include/rtems/confdefs/wkspace.h
+++ b/cpukit/include/rtems/confdefs/wkspace.h
@@ -132,12 +132,14 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
#if defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
&& defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
+ /* Custom allocator may or may not use the work space. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
const bool _Stack_Allocator_avoids_workspace = true;
#else
const bool _Stack_Allocator_avoids_workspace = false;
#endif
+ /* Custom allocator may or may not need initialization. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_INIT
const Stack_Allocator_initialize _Stack_Allocator_initialize =
CONFIGURE_TASK_STACK_ALLOCATOR_INIT;
@@ -145,16 +147,30 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
const Stack_Allocator_initialize _Stack_Allocator_initialize = NULL;
#endif
+ /* Custom allocator must include allocate and free */
const Stack_Allocator_allocate _Stack_Allocator_allocate =
CONFIGURE_TASK_STACK_ALLOCATOR;
const Stack_Allocator_free _Stack_Allocator_free =
CONFIGURE_TASK_STACK_DEALLOCATOR;
+
+/*
+ * Must provide both a custom stack allocator and deallocator
+ */
#elif defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|| defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
#error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
#endif
+/*
+ * Custom IDLE thread stacks allocator. If this is provided, it is assumed
+ * that the allocator is providing its own memory for these stacks.
+ */
+#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
+#endif
+
#ifdef CONFIGURE_DIRTY_MEMORY
RTEMS_SYSINIT_ITEM(
_Memory_Dirty_free_areas,
diff --git a/cpukit/include/rtems/config.h b/cpukit/include/rtems/config.h
index e82c7abf11..a826581658 100644
--- a/cpukit/include/rtems/config.h
+++ b/cpukit/include/rtems/config.h
@@ -129,6 +129,9 @@ uint32_t rtems_configuration_get_maximum_extensions( void );
#define rtems_configuration_get_stack_free_hook() \
(_Stack_Allocator_free)
+#define rtems_configuration_get_stack_allocate_for_idle_hook() \
+ (_Stack_Allocator_allocate_for_idle)
+
/**
* This macro assists in accessing the field which indicates whether
* RTEMS is responsible for zeroing the Executive Workspace.
diff --git a/cpukit/include/rtems/linkersets.h b/cpukit/include/rtems/linkersets.h
index 844130f0d4..d3ed76043a 100644
--- a/cpukit/include/rtems/linkersets.h
+++ b/cpukit/include/rtems/linkersets.h
@@ -38,7 +38,7 @@ extern "C" {
RTEMS_SECTION( ".rtemsroset." #set ".end" ) RTEMS_USED
#define RTEMS_LINKER_ROSET_ITEM_ORDERED_DECLARE( set, type, item, order ) \
- type const _Linker_set_##set##_##item \
+ extern type const _Linker_set_##set##_##item \
RTEMS_SECTION( ".rtemsroset." #set ".content.0." RTEMS_XSTRING( order ) )
#define RTEMS_LINKER_ROSET_ITEM_DECLARE( set, type, item ) \
diff --git a/cpukit/include/rtems/posix/muteximpl.h b/cpukit/include/rtems/posix/muteximpl.h
index 435b43634d..3d717420f2 100644
--- a/cpukit/include/rtems/posix/muteximpl.h
+++ b/cpukit/include/rtems/posix/muteximpl.h
@@ -2,8 +2,8 @@
* @file
*
* @brief Private Inlined Routines for POSIX Mutex's.
- *
- * This include file contains the static inline implementation of the private
+ *
+ * This include file contains the static inline implementation of the private
* inlined routines for POSIX mutex's.
*/
@@ -104,7 +104,7 @@ RTEMS_INLINE_ROUTINE POSIX_Mutex_Protocol _POSIX_Mutex_Get_protocol(
unsigned long flags
)
{
- return flags & POSIX_MUTEX_PROTOCOL_MASK;
+ return (POSIX_Mutex_Protocol) (flags & POSIX_MUTEX_PROTOCOL_MASK);
}
RTEMS_INLINE_ROUTINE bool _POSIX_Mutex_Is_recursive(
@@ -484,4 +484,3 @@ bool _POSIX_Mutex_Auto_initialization( POSIX_Mutex_Control *the_mutex );
#endif
/* end of include file */
-
diff --git a/cpukit/include/rtems/posix/pthreadattrimpl.h b/cpukit/include/rtems/posix/pthreadattrimpl.h
index b5e02ec1c7..7cd69142a6 100644
--- a/cpukit/include/rtems/posix/pthreadattrimpl.h
+++ b/cpukit/include/rtems/posix/pthreadattrimpl.h
@@ -72,7 +72,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Threads_Get_sched_param_sporadic(
#if defined(RTEMS_POSIX_API)
const POSIX_API_Control *api;
- api = the_thread->API_Extensions[ THREAD_API_POSIX ];
+ api = (const POSIX_API_Control*) the_thread->API_Extensions[ THREAD_API_POSIX ];
param->sched_ss_low_priority = _POSIX_Priority_From_core(
scheduler,
api->Sporadic.Low_priority.priority
diff --git a/cpukit/include/rtems/rtl/rtl-obj.h b/cpukit/include/rtems/rtl/rtl-obj.h
index f27ae3259d..c1fe51306b 100644
--- a/cpukit/include/rtems/rtl/rtl-obj.h
+++ b/cpukit/include/rtems/rtl/rtl-obj.h
@@ -231,7 +231,7 @@ struct rtems_rtl_obj
size_t tramps_size; /**< Size of the trampoline memory. */
void* tramp_brk; /**< Trampoline memory allocator. MD
* relocators can take memory from the
- * break upto the size. */
+ * break up to the size. */
size_t tramp_relocs; /**< Number of slots reserved for
* relocs. The remainder are for
* unresolved symbols. */
@@ -333,7 +333,7 @@ static inline bool rtems_rtl_obj_text_inside (const rtems_rtl_obj* obj,
{
return
(address >= obj->text_base) &&
- (address < (obj->text_base + obj->text_size));
+ ((char*) address < ((char*) obj->text_base + obj->text_size));
}
/**
@@ -374,11 +374,23 @@ static inline bool rtems_rtl_obj_has_symbol (const rtems_rtl_obj* obj,
* @param size The size to be allocated.
* @retval bool Returns @true if the space is available.
*/
+static inline size_t rtems_rtl_obj_tramp_avail_space (const rtems_rtl_obj* obj)
+{
+ return (char*) obj->tramp_brk - (char*) obj->trampoline;
+}
+
+/**
+ * Is there space in the trampoline memory for a trapoline.
+ *
+ * @param obj The object file's descriptor to check for available space.
+ * @param size The size to be allocated.
+ * @retval bool Returns @true if the space is available.
+ */
static inline bool rtems_rtl_obj_has_tramp_space (const rtems_rtl_obj* obj,
const size_t size)
{
return (obj->trampoline != NULL &&
- ((obj->tramp_brk - obj->trampoline) + size) <= obj->tramps_size);
+ (rtems_rtl_obj_tramp_avail_space (obj) + size) <= obj->tramps_size);
}
/**
@@ -402,7 +414,7 @@ static inline size_t rtems_rtl_obj_trampoline_slots (const rtems_rtl_obj* obj)
static inline size_t rtems_rtl_obj_trampolines (const rtems_rtl_obj* obj)
{
return obj->trampoline == NULL || obj->tramp_size == 0 ?
- 0 : (obj->tramp_brk - obj->trampoline) / obj->tramp_size;
+ 0 : rtems_rtl_obj_tramp_avail_space (obj) / obj->tramp_size;
}
/**
diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h
index 67d7e96be3..3c74370187 100644
--- a/cpukit/include/rtems/rtl/rtl.h
+++ b/cpukit/include/rtems/rtl/rtl.h
@@ -88,7 +88,7 @@ extern struct r_debug _rtld_debug;
* Debugger break function. Call when debugging to have it read the _rtld_debug
* variable.
*/
-extern void _rtld_debug_state (void);
+void _rtld_debug_state (void);
/**
* The type of constructor/destructor function.
diff --git a/cpukit/include/rtems/score/corebarrierimpl.h b/cpukit/include/rtems/score/corebarrierimpl.h
index 9e9ddfd81e..13e052dc57 100644
--- a/cpukit/include/rtems/score/corebarrierimpl.h
+++ b/cpukit/include/rtems/score/corebarrierimpl.h
@@ -35,7 +35,14 @@ extern "C" {
* @{
*/
-#define CORE_BARRIER_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
+/**
+ * @brief These thread queue operations are used for core barriers.
+ *
+ * They are a specialization of ::_Thread_queue_Operations_FIFO. The only
+ * difference is that the extract operation decrements
+ * CORE_barrier_Control::number_of_waiting_threads.
+ */
+extern const Thread_queue_Operations _CORE_barrier_Thread_queue_operations;
/**
* @brief Initializes the core barrier.
diff --git a/cpukit/include/rtems/score/cpustdatomic.h b/cpukit/include/rtems/score/cpustdatomic.h
index 31a17932c6..8401f68e31 100644
--- a/cpukit/include/rtems/score/cpustdatomic.h
+++ b/cpukit/include/rtems/score/cpustdatomic.h
@@ -294,7 +294,7 @@ static inline uintptr_t _CPU_atomic_Load_uintptr( const CPU_atomic_Uintptr *obj,
static inline void _CPU_atomic_Store_uint( CPU_atomic_Uint *obj, unsigned int desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
@@ -314,7 +314,7 @@ static inline void _CPU_atomic_Store_uint( CPU_atomic_Uint *obj, unsigned int de
static inline void _CPU_atomic_Store_ulong( CPU_atomic_Ulong *obj, unsigned long desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
@@ -334,7 +334,7 @@ static inline void _CPU_atomic_Store_ulong( CPU_atomic_Ulong *obj, unsigned long
static inline void _CPU_atomic_Store_uintptr( CPU_atomic_Uintptr *obj, uintptr_t desired, CPU_atomic_Order order )
{
#if defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_ATOMIC)
- obj->store( desired );
+ obj->store( desired, order );
#elif defined(_RTEMS_SCORE_CPUSTDATOMIC_USE_STDATOMIC)
atomic_store_explicit( obj, desired, order );
#else
diff --git a/cpukit/include/rtems/score/heapimpl.h b/cpukit/include/rtems/score/heapimpl.h
index d3ee0ff88a..f74b5fc562 100644
--- a/cpukit/include/rtems/score/heapimpl.h
+++ b/cpukit/include/rtems/score/heapimpl.h
@@ -407,15 +407,7 @@ Heap_Block *_Heap_Block_allocate(
(*heap->Protection.block_error)( heap, block, reason );
}
- static inline void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap )
- {
- uintptr_t large = 0
- - (uintptr_t) HEAP_BLOCK_HEADER_SIZE
- - (uintptr_t) HEAP_ALLOC_BONUS
- - (uintptr_t) 1;
- void *p = _Heap_Allocate( heap, large );
- _Heap_Free( heap, p );
- }
+ void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap );
#endif
/**
diff --git a/cpukit/include/rtems/score/objectimpl.h b/cpukit/include/rtems/score/objectimpl.h
index c540f90166..ed0ce2aa10 100644
--- a/cpukit/include/rtems/score/objectimpl.h
+++ b/cpukit/include/rtems/score/objectimpl.h
@@ -938,6 +938,25 @@ RTEMS_INLINE_ROUTINE void _Objects_Free(
}
/**
+ * @brief Returns true, if the object associated with the zero-based index is
+ * contained in an allocated block of objects, otherwise false.
+ *
+ * @param index is the zero-based object index.
+ * @param objects_per_block is the object count per block.
+ *
+ * @retval true The object associated with the zero-based index is in an
+ * allocated block of objects.
+ * @retval false Otherwise.
+ */
+RTEMS_INLINE_ROUTINE bool _Objects_Is_in_allocated_block(
+ Objects_Maximum index,
+ Objects_Maximum objects_per_block
+)
+{
+ return index >= objects_per_block;
+}
+
+/**
* @brief Activate the object.
*
* This function must be only used in case this objects information supports
@@ -952,15 +971,17 @@ RTEMS_INLINE_ROUTINE void _Objects_Activate_unlimited(
)
{
Objects_Maximum objects_per_block;
- Objects_Maximum block;
+ Objects_Maximum index;
_Assert( _Objects_Is_auto_extend( information ) );
objects_per_block = information->objects_per_block;
- block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+ index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+
+ if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) {
+ Objects_Maximum block;
- if ( block > objects_per_block ) {
- block /= objects_per_block;
+ block = index / objects_per_block;
information->inactive_per_block[ block ]--;
information->inactive--;
diff --git a/cpukit/include/rtems/score/priority.h b/cpukit/include/rtems/score/priority.h
index 54b91a871b..a6c65d3c4c 100644
--- a/cpukit/include/rtems/score/priority.h
+++ b/cpukit/include/rtems/score/priority.h
@@ -24,12 +24,12 @@
#include <rtems/score/cpu.h>
#include <rtems/score/rbtree.h>
-struct _Scheduler_Control;
-
#ifdef __cplusplus
extern "C" {
#endif
+struct _Scheduler_Control;
+
/**
* @defgroup RTEMSScorePriority Priority Handler
*
diff --git a/cpukit/include/rtems/score/priorityimpl.h b/cpukit/include/rtems/score/priorityimpl.h
index b33419acdb..3b92d3375a 100644
--- a/cpukit/include/rtems/score/priorityimpl.h
+++ b/cpukit/include/rtems/score/priorityimpl.h
@@ -389,7 +389,7 @@ RTEMS_INLINE_ROUTINE bool _Priority_Less(
const Priority_Control *the_left;
const Priority_Node *the_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Priority_Node, Node.RBTree );
return *the_left < the_right->priority;
diff --git a/cpukit/include/rtems/score/scheduleredfimpl.h b/cpukit/include/rtems/score/scheduleredfimpl.h
index f2bec2dfbe..fc8c67c163 100644
--- a/cpukit/include/rtems/score/scheduleredfimpl.h
+++ b/cpukit/include/rtems/score/scheduleredfimpl.h
@@ -100,7 +100,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Less(
Priority_Control prio_left;
Priority_Control prio_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
prio_left = *the_left;
@@ -128,7 +128,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Priority_less_equal(
Priority_Control prio_left;
Priority_Control prio_right;
- the_left = left;
+ the_left = (const Priority_Control*) left;
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
prio_left = *the_left;
diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h
index df1df74867..bad89e66fc 100644
--- a/cpukit/include/rtems/score/stack.h
+++ b/cpukit/include/rtems/score/stack.h
@@ -82,6 +82,23 @@ typedef void *( *Stack_Allocator_allocate )( size_t stack_size );
typedef void ( *Stack_Allocator_free )( void *addr );
/**
+ * @brief Stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * @param cpu Index of the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory.
+ * @retval other Pointer to begin of stack area.
+ */
+typedef void *( *Stack_Allocator_allocate_for_idle )(
+ uint32_t cpu,
+ size_t stack_size
+);
+
+/**
* @brief The minimum stack size.
*
* Application provided via <rtems/confdefs.h>.
@@ -124,6 +141,13 @@ extern const Stack_Allocator_allocate _Stack_Allocator_allocate;
extern const Stack_Allocator_free _Stack_Allocator_free;
/** @} */
+/**
+ * @brief The stack allocator allocate stack for idle thread handler.
+ *
+ * Application provided via <rtems/confdefs.h>.
+ */
+extern const Stack_Allocator_allocate_for_idle
+ _Stack_Allocator_allocate_for_idle;
#ifdef __cplusplus
}
diff --git a/cpukit/include/rtems/score/threadq.h b/cpukit/include/rtems/score/threadq.h
index 522be03970..29d3fafda6 100644
--- a/cpukit/include/rtems/score/threadq.h
+++ b/cpukit/include/rtems/score/threadq.h
@@ -497,16 +497,17 @@ typedef Thread_Control *( *Thread_queue_Surrender_operation )(
);
/**
- * @brief Thread queue first operation.
+ * @brief Gets the first thread on the queue.
*
- * @param[in] heads The thread queue heads.
+ * @param heads are heads of the thread queue.
*
- * @retval NULL No thread is present on the thread queue.
- * @retval first The first thread of the thread queue according to the insert
- * order. This thread remains on the thread queue.
+ * @retval NULL No thread is enqueued on the thread queue.
+ *
+ * @return Returns the first thread on the thread queue according to the queue
+ * order. This thread remains on the thread queue.
*/
typedef Thread_Control *( *Thread_queue_First_operation )(
- Thread_queue_Heads *heads
+ const Thread_queue_Heads *heads
);
/**
diff --git a/cpukit/include/rtems/score/threadqops.h b/cpukit/include/rtems/score/threadqops.h
new file mode 100644
index 0000000000..504383e98d
--- /dev/null
+++ b/cpukit/include/rtems/score/threadqops.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSScoreThreadQueue
+ *
+ * @brief This header file provides interfaces related to thread queue
+ * operations.
+ */
+
+/*
+ * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTEMS_SCORE_THREADQOPS_H
+#define _RTEMS_SCORE_THREADQOPS_H
+
+#include <rtems/score/threadq.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup RTEMSScoreThreadQueue
+ *
+ * @{
+ */
+
+/**
+ * @brief Initializes the priority actions so that no actions are performed.
+ *
+ * @param queue is unused.
+ *
+ * @param[out] priority_actions is initialized so that no actions are
+ * performed.
+ */
+void _Thread_queue_Do_nothing_priority_actions(
+ Thread_queue_Queue *queue,
+ Priority_Actions *priority_actions
+);
+
+/**
+ * @brief Enqueues the thread to the FIFO thread queue.
+ *
+ * @param[in, out] queue is the thread queue.
+ *
+ * @param[in, out] the_thread is the thread to enqueue.
+ *
+ * @param[in, out] queue_context is the thread queue context.
+ */
+void _Thread_queue_FIFO_enqueue(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Extracts the thread from the FIFO thread queue.
+ *
+ * @param[in, out] queue is the thread queue.
+ *
+ * @param[in, out] the_thread is the thread to extract.
+ *
+ * @param[in, out] queue_context is the thread queue context.
+ */
+void _Thread_queue_FIFO_extract(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Surrenders the thread queue to the first thread on the FIFO thread
+ * queue.
+ *
+ * @param[in, out] queue is the thread queue.
+ *
+ * @param[in, out] heads are heads of the thread queue.
+ *
+ * @param previous_owner is unused.
+ *
+ * @param[in, out] queue_context is the thread queue context.
+ *
+ * @return Returns the first thread on the thread queue according to the queue
+ * order.
+ */
+Thread_Control *_Thread_queue_FIFO_surrender(
+ Thread_queue_Queue *queue,
+ Thread_queue_Heads *heads,
+ Thread_Control *previous_owner,
+ Thread_queue_Context *queue_context
+);
+
+/**
+ * @brief Gets the first thread on the FIFO thread queue.
+ *
+ * @param[in, out] queue is the thread queue.
+ *
+ * @param[in, out] the_thread is the thread to extract.
+ *
+ * @param[in, out] queue_context is the thread queue context.
+ */
+Thread_Control *_Thread_queue_FIFO_first( const Thread_queue_Heads *heads );
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTEMS_SCORE_THREADQOPS_H */
diff --git a/cpukit/include/rtems/score/timecounter.h b/cpukit/include/rtems/score/timecounter.h
index b71ccd3948..64429eae7b 100644
--- a/cpukit/include/rtems/score/timecounter.h
+++ b/cpukit/include/rtems/score/timecounter.h
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (c) 2015 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2015, 2021 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -247,6 +247,28 @@ extern volatile int32_t _Timecounter_Time_uptime;
*/
extern struct timecounter *_Timecounter;
+/**
+ * @brief Handler doing the NTP update second processing shall have this type.
+ *
+ * @param[in, out] adjustment is the NTP time adjustment.
+ *
+ * @param[in, out] newsec is the number of seconds since Unix epoch.
+ */
+typedef void ( *Timecounter_NTP_update_second )(
+ int64_t *adjustment,
+ time_t *newsec
+);
+
+/**
+ * @brief Sets the NTP update second handler.
+ *
+ * @param handler is the new NTP update second handler used to carry out the
+ * NTP update second processing.
+ */
+void _Timecounter_Set_NTP_update_second(
+ Timecounter_NTP_update_second handler
+);
+
/** @} */
#ifdef __cplusplus
diff --git a/cpukit/include/rtems/score/tls.h b/cpukit/include/rtems/score/tls.h
index 65a49d87be..322be30c7a 100644
--- a/cpukit/include/rtems/score/tls.h
+++ b/cpukit/include/rtems/score/tls.h
@@ -222,7 +222,7 @@ static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
{
void *tls_block = (char *) tls_area
+ _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
- TLS_Thread_control_block *tcb = tls_area;
+ TLS_Thread_control_block *tcb = (TLS_Thread_control_block*) tls_area;
uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
((char *) tls_block + aligned_size);
diff --git a/cpukit/include/rtems/score/watchdogimpl.h b/cpukit/include/rtems/score/watchdogimpl.h
index a52fb1c2cb..ed9d1ef5cd 100644
--- a/cpukit/include/rtems/score/watchdogimpl.h
+++ b/cpukit/include/rtems/score/watchdogimpl.h
@@ -150,7 +150,7 @@ RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
const Watchdog_Control *the_watchdog
)
{
- return RB_COLOR( &the_watchdog->Node.RBTree, Node );
+ return (Watchdog_State) RB_COLOR( &the_watchdog->Node.RBTree, Node );
}
/**
diff --git a/cpukit/include/rtems/shellconfig.h b/cpukit/include/rtems/shellconfig.h
index 3e87d472d6..c5fcf4a45e 100644
--- a/cpukit/include/rtems/shellconfig.h
+++ b/cpukit/include/rtems/shellconfig.h
@@ -78,6 +78,10 @@ extern rtems_shell_cmd_t rtems_shell_DF_Command;
extern rtems_shell_cmd_t rtems_shell_MD5_Command;
extern rtems_shell_cmd_t rtems_shell_RTC_Command;
+extern rtems_shell_cmd_t rtems_shell_SPI_Command;
+extern rtems_shell_cmd_t rtems_shell_I2CDETECT_Command;
+extern rtems_shell_cmd_t rtems_shell_I2CGET_Command;
+extern rtems_shell_cmd_t rtems_shell_I2CSET_Command;
extern rtems_shell_cmd_t rtems_shell_SHUTDOWN_Command;
extern rtems_shell_cmd_t rtems_shell_CPUINFO_Command;
@@ -521,6 +525,30 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[];
&rtems_shell_RTC_Command,
#endif
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
+ && !defined(CONFIGURE_SHELL_NO_COMMAND_SPI)) \
+ || defined(CONFIGURE_SHELL_COMMAND_SPI)
+ &rtems_shell_SPI_Command,
+ #endif
+
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
+ && !defined(CONFIGURE_SHELL_NO_COMMAND_I2CDETECT)) \
+ || defined(CONFIGURE_SHELL_COMMAND_I2CDETECT)
+ &rtems_shell_I2CDETECT_Command,
+ #endif
+
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
+ && !defined(CONFIGURE_SHELL_NO_COMMAND_I2CGET)) \
+ || defined(CONFIGURE_SHELL_COMMAND_I2CGET)
+ &rtems_shell_I2CGET_Command,
+ #endif
+
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
+ && !defined(CONFIGURE_SHELL_NO_COMMAND_I2CSET)) \
+ || defined(CONFIGURE_SHELL_COMMAND_I2CSET)
+ &rtems_shell_I2CSET_Command,
+ #endif
+
/*
* System related commands
*/
diff --git a/cpukit/include/rtems/termiostypes.h b/cpukit/include/rtems/termiostypes.h
index 6930e5958b..59b1b3dd96 100644
--- a/cpukit/include/rtems/termiostypes.h
+++ b/cpukit/include/rtems/termiostypes.h
@@ -367,6 +367,10 @@ typedef struct rtems_termios_tty {
*/
rtems_id rxTaskId;
rtems_id txTaskId;
+ /*
+ * Information for the tx task how many characters have been dequeued.
+ */
+ int txTaskCharsDequeued;
/*
* line discipline related stuff
@@ -482,7 +486,7 @@ struct rtems_termios_linesw {
int (*l_read )(struct rtems_termios_tty *tp,rtems_libio_rw_args_t *args);
int (*l_write)(struct rtems_termios_tty *tp,rtems_libio_rw_args_t *args);
int (*l_rint )(int c,struct rtems_termios_tty *tp);
- int (*l_start)(struct rtems_termios_tty *tp);
+ int (*l_start)(struct rtems_termios_tty *tp,int len);
int (*l_ioctl)(struct rtems_termios_tty *tp,rtems_libio_ioctl_args_t *args);
int (*l_modem)(struct rtems_termios_tty *tp,int flags);
};
diff --git a/cpukit/include/rtems/version.h b/cpukit/include/rtems/version.h
index a8aff732f3..24104022b5 100644
--- a/cpukit/include/rtems/version.h
+++ b/cpukit/include/rtems/version.h
@@ -29,6 +29,27 @@ extern "C" {
*
* @brief The Version API provides functions to return the version or parts of
* the version of RTEMS you are using.
+ *
+ * A branch in the version control system will always fall back to a
+ * NOT-RELEASED version number with a minor number of 0. Only the release
+ * archives have a VERSION file with a final release number. That means for
+ * example that the 5 development branch will still show a version 5.0.0 even
+ * after the 5.1 release.
+ *
+ * The reason for that are the following:
+ *
+ * 1. All pre-release tests are performed with a specific git hash. A committed
+ * VERSION file would need to be changed and committed afterwards for releasing
+ * with the required release version causing the released version to have a
+ * different git hash and the test results couldn't be linked to the released
+ * version.
+ *
+ * 2. Users deploying RTEMS would need to commit a local change to a committed
+ * VERSION file and that would clash with the project changes. Deployment can
+ * use the project repos directly.
+ *
+ * 3. The VERSION file management and generation is the responsibility of the
+ * release manager and the release process.
*/
/**@{**/
diff --git a/cpukit/libcsupport/src/posix_devctl.c b/cpukit/libcsupport/src/posix_devctl.c
index 3ff9dd929f..d875895b84 100644
--- a/cpukit/libcsupport/src/posix_devctl.c
+++ b/cpukit/libcsupport/src/posix_devctl.c
@@ -35,6 +35,7 @@
#include <rtems/seterr.h>
#include <unistd.h>
+#include <fcntl.h>
int posix_devctl(
int fd,
@@ -44,6 +45,15 @@ int posix_devctl(
int *__restrict dev_info_ptr
)
{
+ int rv = 0;
+
+ /*
+ * posix_devctl() is supposed to return an errno. eerno needs to be
+ * preserved in spite of calling methods (e.g., close, fcntl, and ioctl)
+ * that set it.
+ */
+ int errno_copy = errno;
+
/*
* The POSIX 1003.26 standard allows for library implementations
* that implement posix_devctl() using ioctl(). In this case,
@@ -72,15 +82,69 @@ int posix_devctl(
}
/*
- * The FACE Technical Standard Edition 3.0 and newer requires the SOCKCLOSE
- * ioctl command. This is because the Security Profile does not include
- * close() and applications need a way to close sockets. Closing sockets is
- * a minimum requirement so using close() in the implementation meets that
- * requirement but also lets the application close other file types.
+ *
*/
- if (dcmd == SOCKCLOSE ) {
- return close(fd);
+ switch (dcmd) {
+
+ /*
+ * The FACE Technical Standard Edition 3.0 and newer requires the SOCKCLOSE
+ * ioctl command. This is because the Security Profile does not include
+ * close() and applications need a way to close sockets. Closing sockets is
+ * a minimum requirement so using close() in the implementation meets that
+ * requirement but also lets the application close other file types.
+ */
+ case SOCKCLOSE:
+ if (close(fd) != 0) {
+ rv = errno;
+ errno = errno_copy;
+
+ return rv;
+ }
+ break;
+
+ /*
+ * The FACE Technical Standard Edition 3.0 and newer requires the
+ * posix_devctl command to support the FIONBIO subcommand.
+ */
+ case FIONBIO: {
+ int tmp_flag;
+ int flag;
+
+ if (nbyte != sizeof(int)) {
+ return EINVAL;
+ }
+
+ tmp_flag = fcntl(fd, F_GETFL, 0);
+ if (tmp_flag == -1) {
+ rv = errno;
+ errno = errno_copy;
+
+ return rv;
+ }
+
+ flag = *(int *)dev_data_ptr;
+
+ if (flag != 0) {
+ tmp_flag |= O_NONBLOCK;
+ } else {
+ tmp_flag &= ~O_NONBLOCK;
+ }
+
+ (void) fcntl(fd, F_SETFL, tmp_flag);
+ break;
+ }
+
+ default:
+ if (ioctl(fd, dcmd, dev_data_ptr) != 0) {
+ rv = errno;
+ errno = errno_copy;
+
+ return errno;
+ }
+ break;
}
- return ioctl(fd, dcmd, dev_data_ptr);
+ errno = errno_copy;
+
+ return rv;
}
diff --git a/cpukit/libcsupport/src/sync.c b/cpukit/libcsupport/src/sync.c
index 265c6f07c9..0ea77422f1 100644
--- a/cpukit/libcsupport/src/sync.c
+++ b/cpukit/libcsupport/src/sync.c
@@ -1,13 +1,13 @@
/**
- * @file
+ * @file
*
- * @brief Synchronize Data on Disk with Memory
- * @ingroup libcsupport
+ * @ingroup libcsupport
+ *
+ * @brief This source file contains the implementation of sync().
*/
/*
- * COPYRIGHT (c) 1989-2008.
- * On-Line Applications Research Corporation (OAR).
+ * Copyright (C) 2022 embedded brains GmbH
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -18,85 +18,16 @@
#include "config.h"
#endif
-/* Since we compile with strict ANSI we need to undef it to get
- * prototypes for extensions
- */
-#undef __STRICT_ANSI__
-int fdatasync(int); /* still not always prototyped */
-
-
#include <unistd.h>
-#include <stdio.h>
-
-#include <rtems.h>
-#include <rtems/score/thread.h>
-#include <rtems/score/percpu.h>
-
-/* XXX check standards -- Linux version appears to be void */
-void _fwalk(struct _reent *, void *);
-
-
-static void sync_wrapper(FILE *f)
-{
- int fn = fileno(f);
-
- /*
- * There is no way to report errors here. So this is a best-effort approach.
- */
- (void) fsync(fn);
- (void) fdatasync(fn);
-}
-/* iterate over all FILE *'s for this thread */
-static bool sync_per_thread(Thread_Control *t, void *arg)
-{
- struct _reent *current_reent;
- struct _reent *this_reent;
-
- /*
- * The sync_wrapper() function will operate on the current thread's
- * reent structure so we will temporarily use that.
- */
- this_reent = t->libc_reent;
- if ( this_reent ) {
- Thread_Control *executing = _Thread_Get_executing();
- current_reent = executing->libc_reent;
- executing->libc_reent = this_reent;
- _fwalk (t->libc_reent, sync_wrapper);
- executing->libc_reent = current_reent;
- }
-
- return false;
-}
+#include <rtems/libio_.h>
-/*
- * _global_impure_ptr is not prototyped in any .h files.
- * We have to extern it here.
- */
-extern struct _reent * const _global_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
-
-/**
- * This function operates by as follows:
- * for all threads
- * for all FILE *
- * fsync()
- * fdatasync()
- */
-void sync(void)
+void sync( void )
{
+ int fd;
- /*
- * Walk the one used initially by RTEMS.
- */
- _fwalk(_global_impure_ptr, sync_wrapper);
-
- /*
- * XXX Do we walk the one used globally by newlib?
- * XXX Do we need the RTEMS global one?
- */
-
- /*
- * Now walk all the per-thread reentrancy structures.
- */
- rtems_task_iterate(sync_per_thread, NULL);
+ for ( fd = 0; fd < (int) rtems_libio_number_iops; ++fd ) {
+ (void) fsync( fd );
+ (void) fdatasync( fd );
+ }
}
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index 75925cf8ec..2b354203e9 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -1966,6 +1966,7 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
/*
* send wake up to transmitter task
*/
+ tty->txTaskCharsDequeued = len;
sc = rtems_event_send(tty->txTaskId, TERMIOS_TX_START_EVENT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
@@ -1977,7 +1978,7 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
* call PPP line discipline start function
*/
if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
- rtems_termios_linesw[tty->t_line].l_start(tty);
+ rtems_termios_linesw[tty->t_line].l_start(tty, len);
}
return 0; /* nothing to output in IRQ... */
}
@@ -2012,7 +2013,7 @@ static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
* call any line discipline start function
*/
if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
- rtems_termios_linesw[tty->t_line].l_start(tty);
+ rtems_termios_linesw[tty->t_line].l_start(tty, tty->txTaskCharsDequeued);
if (tty->t_line == PPPDISC) {
/*
diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c
index 0f19859fac..b6cd7812f2 100644
--- a/cpukit/libfs/src/imfs/imfs_memfile.c
+++ b/cpukit/libfs/src/imfs/imfs_memfile.c
@@ -189,9 +189,10 @@ static int IMFS_memfile_extend(
offset = 0;
}
} else {
- for ( ; block>=old_blocks ; block-- ) {
+ for ( ; block>old_blocks ; block-- ) {
IMFS_memfile_remove_block( memfile, block );
}
+ IMFS_memfile_remove_block( memfile, old_blocks );
rtems_set_errno_and_return_minus_one( ENOSPC );
}
}
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.c b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
index 39e70bffec..0c8ccfd2c2 100644
--- a/cpukit/libmisc/rtems-fdt/rtems-fdt.c
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
@@ -163,7 +163,7 @@ rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob)
}
names = calloc(1, total_name_memory);
- if (!entries)
+ if (!names)
{
free(entries);
return -RTEMS_FDT_ERR_NO_MEMORY;
@@ -582,7 +582,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle)
close (bf);
return -RTEMS_FDT_ERR_READ_FAIL;
}
- r -= size;
+ size -= r;
buf += r;
}
}
@@ -680,14 +680,14 @@ rtems_fdt_unload (rtems_fdt_handle* handle)
rtems_chain_extract_unprotected (&handle->blob->node);
+ rtems_fdt_release_index(&handle->blob->index);
+
free (handle->blob);
handle->blob = NULL;
rtems_fdt_unlock (fdt);
- rtems_fdt_release_index(&handle->blob->index);
-
return 0;
}
diff --git a/cpukit/libmisc/shell/main_chmod.c b/cpukit/libmisc/shell/main_chmod.c
index 0c39072f6b..288fd52f4c 100644
--- a/cpukit/libmisc/shell/main_chmod.c
+++ b/cpukit/libmisc/shell/main_chmod.c
@@ -53,7 +53,7 @@ static int rtems_shell_main_chmod(
* Now change the files modes
*/
for (n=2 ; n < argc ; n++)
- chmod(argv[n++], mode);
+ chmod(argv[n], mode);
return 0;
}
diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c
index e43ff68d2b..681e8c5f3c 100644
--- a/cpukit/libmisc/shell/main_edit.c
+++ b/cpukit/libmisc/shell/main_edit.c
@@ -407,6 +407,9 @@ static void move_gap(struct editor *ed, int pos, int minsize) {
if (gapsize + MINEXTEND > minsize) minsize = gapsize + MINEXTEND;
newsize = (ed->end - ed->start) - gapsize + minsize;
start = (unsigned char *) malloc(newsize); // TODO check for out of memory
+ if (start == NULL) {
+ return;
+ }
gap = start + pos;
rest = gap + minsize;
end = start + newsize;
@@ -1789,14 +1792,14 @@ static void save_editor(struct editor *ed) {
ed->refresh = 1;
}
-static void close_editor(struct editor *ed) {
+static struct editor* close_editor(struct editor *ed) {
struct env *env = ed->env;
if (ed->dirty) {
display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
if (!ask()) {
ed->refresh = 1;
- return;
+ return ed;
}
}
@@ -1808,6 +1811,7 @@ static void close_editor(struct editor *ed) {
new_file(ed, "");
}
ed->refresh = 1;
+ return ed;
}
static void pipe_command(struct editor *ed) {
@@ -2131,15 +2135,7 @@ static void edit(struct editor *ed) {
case ctrl('s'): save_editor(ed); break;
case ctrl('p'): pipe_command(ed); break;
#endif
-#if defined(__rtems__)
- /*
- * Coverity spotted this as using ed after free() so changing
- * the order of the statements.
- */
- case ctrl('w'): ed = ed->env->current; close_editor(ed); break;
-#else
- case ctrl('w'): close_editor(ed); ed = ed->env->current; break;
-#endif
+ case ctrl('w'): ed = close_editor(ed); break;
}
}
}
diff --git a/cpukit/libmisc/shell/main_i2cdetect.c b/cpukit/libmisc/shell/main_i2cdetect.c
new file mode 100644
index 0000000000..e953b4eaef
--- /dev/null
+++ b/cpukit/libmisc/shell/main_i2cdetect.c
@@ -0,0 +1,107 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The command implemented here has a similar interface like the one from Linux
+ * i2c tools. Think of it as a heavily simplified version of them. Instead of
+ * the bus number they expect a bus path.
+ */
+
+#include <dev/i2c/i2c.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rtems/shell.h>
+
+static const char rtems_i2cdetect_shell_usage [] =
+ "i2cdetect <I2C_BUS>\n"
+ "\ttry to detect i2c devices on the given bus\n";
+
+static int rtems_i2cdetect_shell_main(int argc, char *argv[])
+{
+ int fd;
+ int rv;
+ const char *bus;
+ const uint16_t first = 1;
+ const uint16_t last = 0x7f;
+ uint16_t current;
+
+ if (argc != 2 || strcmp(argv[1], "-h") == 0) {
+ printf(rtems_i2cdetect_shell_usage);
+ return 1;
+ }
+
+ bus = argv[1];
+ fd = open(bus, O_RDWR);
+ if (fd < 0) {
+ perror("Couldn't open bus");
+ return 1;
+ }
+
+ printf(" x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF\n"
+ "0x ");
+ for (current = first; current <= last; ++current) {
+ i2c_msg msg = {
+ .addr = current,
+ .flags = 0,
+ .len = 0,
+ .buf = NULL,
+ };
+
+ struct i2c_rdwr_ioctl_data payload = {
+ .msgs = &msg,
+ .nmsgs = 1,
+ };
+
+ if ((current & 0x0F) == 0) {
+ printf("\n%1xx ", current >> 4);
+ }
+
+ rv = ioctl(fd, I2C_RDWR, &payload);
+ if (rv < 0) {
+ if (errno != EIO) {
+ perror("ioctl failed");
+ }
+ printf(" --");
+ } else {
+ printf(" %02x", current);
+ }
+ }
+ printf("\n");
+ close(fd);
+
+ return 0;
+}
+
+rtems_shell_cmd_t rtems_shell_I2CDETECT_Command = {
+ .name = "i2cdetect",
+ .usage = rtems_i2cdetect_shell_usage,
+ .topic = "misc",
+ .command = rtems_i2cdetect_shell_main,
+};
diff --git a/cpukit/libmisc/shell/main_i2cget.c b/cpukit/libmisc/shell/main_i2cget.c
new file mode 100644
index 0000000000..ffa551308b
--- /dev/null
+++ b/cpukit/libmisc/shell/main_i2cget.c
@@ -0,0 +1,145 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The command implemented here has a similar interface like the one from Linux
+ * i2c tools. Think of it as a heavily simplified version of them. Instead of
+ * the bus number they expect a bus path.
+ *
+ * Additionally the i2cget has a continuous read mode that isn't available on
+ * Linux but does something similar to i2cdump.
+ */
+
+#include <dev/i2c/i2c.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rtems/shell.h>
+
+static const char rtems_i2cget_shell_usage [] =
+ "i2cget <I2C_BUS> <CHIP-ADDRESS> <DATA-ADDRESS> [<NR-BYTES>]\n"
+ "\tGet one or more bytes from an EEPROM like i2c device.\n"
+ "\tNote that multiple bytes will be read in continuous mode.\n";
+
+static int read_bytes(
+ int fd,
+ uint16_t i2c_address,
+ uint8_t data_address,
+ uint16_t nr_bytes
+)
+{
+ int rv;
+ uint8_t value[nr_bytes];
+ i2c_msg msgs[] = {{
+ .addr = i2c_address,
+ .flags = 0,
+ .buf = &data_address,
+ .len = 1,
+ }, {
+ .addr = i2c_address,
+ .flags = I2C_M_RD,
+ .buf = value,
+ .len = nr_bytes,
+ }};
+ struct i2c_rdwr_ioctl_data payload = {
+ .msgs = msgs,
+ .nmsgs = sizeof(msgs)/sizeof(msgs[0]),
+ };
+ uint16_t i;
+
+ rv = ioctl(fd, I2C_RDWR, &payload);
+ if (rv < 0) {
+ perror("ioctl failed");
+ } else {
+ for (i = 0; i < nr_bytes; ++i) {
+ printf("0x%02x ", value[i]);
+ }
+ printf("\n");
+ }
+
+ return rv;
+}
+
+static int rtems_i2cget_shell_main(int argc, char *argv[])
+{
+ int fd;
+ int rv;
+ const char *bus;
+ uint16_t chip_address;
+ uint8_t data_address;
+ uint16_t nr_bytes;
+
+ if (argc < 4 || argc > 5) {
+ printf(rtems_i2cget_shell_usage);
+ return 1;
+ }
+
+ errno = 0;
+ chip_address = (uint16_t) strtoul(argv[2], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read chip address");
+ return 1;
+ }
+
+ errno = 0;
+ data_address = (uint8_t) strtoul(argv[3], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read data address");
+ return 1;
+ }
+
+ nr_bytes = 1;
+ if (argc == 5) {
+ errno = 0;
+ nr_bytes = (uint16_t) strtoul(argv[4], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read number of bytes");
+ return 1;
+ }
+ }
+
+ bus = argv[1];
+ fd = open(bus, O_RDWR);
+ if (fd < 0) {
+ perror("Couldn't open bus");
+ return 1;
+ }
+
+ rv = read_bytes(fd, chip_address, data_address, nr_bytes);
+
+ close(fd);
+
+ return rv;
+}
+
+rtems_shell_cmd_t rtems_shell_I2CGET_Command = {
+ .name = "i2cget",
+ .usage = rtems_i2cget_shell_usage,
+ .topic = "misc",
+ .command = rtems_i2cget_shell_main,
+};
diff --git a/cpukit/libmisc/shell/main_i2cset.c b/cpukit/libmisc/shell/main_i2cset.c
new file mode 100644
index 0000000000..d9025b3b28
--- /dev/null
+++ b/cpukit/libmisc/shell/main_i2cset.c
@@ -0,0 +1,124 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The command implemented here has a similar interface like the one from Linux
+ * i2c tools. Think of it as a heavily simplified version of them. Instead of
+ * the bus number they expect a bus path.
+ *
+ * Additionally it is possible to write multiple values as a continuous write.
+ */
+
+#include <dev/i2c/i2c.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rtems/shell.h>
+
+static const char rtems_i2cset_shell_usage [] =
+ "i2cset <I2C_BUS> <CHIP-ADDRESS> <DATA-ADDRESS> <VALUE> [<VALUE> [...]]\n"
+ "\tset one byte of an EEPROM like i2c device\n";
+
+static int
+rtems_i2cset_shell_main(int argc, char *argv[])
+{
+ int fd;
+ int rv;
+ const char *bus;
+ uint16_t chip_address;
+ /* Necessary: data-address and values. This will be a bit more. */
+ uint8_t writebuff[argc];
+ size_t len;
+ size_t i;
+ i2c_msg msgs[] = {{
+ .flags = 0,
+ .buf = writebuff,
+ .len = 0,
+ }};
+ struct i2c_rdwr_ioctl_data payload = {
+ .msgs = msgs,
+ .nmsgs = sizeof(msgs)/sizeof(msgs[0]),
+ };
+
+ if (argc < 5) {
+ printf(rtems_i2cset_shell_usage);
+ return 1;
+ }
+
+ errno = 0;
+ chip_address = (uint16_t) strtoul(argv[2], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read CHIP_ADDRESS");
+ return 1;
+ }
+ msgs[0].addr = chip_address;
+
+ errno = 0;
+ writebuff[0] = (uint8_t) strtoul(argv[3], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read DATA_ADDRESS");
+ return 1;
+ }
+
+ /* Read values starting from the fifth argument (index 4) */
+ i = 4;
+ len = 0;
+ while (i < argc) {
+ errno = 0;
+ writebuff[len + 1] = (uint8_t) strtoul(argv[i], NULL, 0);
+ if (errno != 0) {
+ perror("Couldn't read VALUE");
+ return 1;
+ }
+ ++i;
+ ++len;
+ }
+ msgs[0].len = len + 1; /* Don't forget address */
+
+ bus = argv[1];
+ fd = open(bus, O_RDWR);
+ if (fd < 0) {
+ perror("Couldn't open bus");
+ return 1;
+ }
+
+ rv = ioctl(fd, I2C_RDWR, &payload);
+ if (rv < 0) {
+ perror("ioctl failed");
+ }
+ close(fd);
+
+ return rv;
+}
+
+rtems_shell_cmd_t rtems_shell_I2CSET_Command = {
+ .name = "i2cset",
+ .usage = rtems_i2cset_shell_usage,
+ .topic = "misc",
+ .command = rtems_i2cset_shell_main,
+};
diff --git a/cpukit/libmisc/shell/main_spi.c b/cpukit/libmisc/shell/main_spi.c
new file mode 100644
index 0000000000..487a22fc6c
--- /dev/null
+++ b/cpukit/libmisc/shell/main_spi.c
@@ -0,0 +1,157 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dev/spi/spi.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rtems/shell.h>
+
+static const char rtems_spi_shell_usage [] =
+ "simple SPI read / write\n"
+ "\n"
+ "spi [-loh] [-c <cs>] [-s <speed>] [-m <mode>] <SPI_BUS> xx [xx [..]]\n"
+ " <SPI_BUS> Bus device to use\n"
+ " xx Hex value of a byte to send\n"
+ " -c <cs> Use chip select <cs> (default: None)\n"
+ " -m <mode> Use SPI mode <mode> (default: 0)\n"
+ " -l Send LSB first\n"
+ " -o Use loopback mode\n"
+ " -s <speed> Bus speed in hz\n"
+ " -h Print this help\n";
+
+static int rtems_spi_shell_main(int argc, char *argv[])
+{
+ uint8_t buffer[argc - 1];
+ size_t len = 0;
+ int i;
+ size_t j;
+ int rv;
+ int fd;
+ char *bus = NULL;
+ unsigned long mode;
+ spi_ioc_transfer msg = {
+ .len = 0,
+ .rx_buf = buffer,
+ .tx_buf = buffer,
+ .speed_hz = 100000,
+ .bits_per_word = 8,
+ .cs_change = true,
+ .mode = SPI_MODE_0 | SPI_NO_CS,
+ };
+
+ for (i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case ('c'):
+ errno = 0;
+ msg.mode &= ~SPI_NO_CS;
+ msg.cs = (uint8_t) strtoul(argv[i+1], NULL, 0);
+ ++i;
+ if (errno != 0) {
+ printf("Couldn't process chip select\n");
+ return 1;
+ }
+ break;
+ case ('m'):
+ errno = 0;
+ mode = strtoul(argv[i+1], NULL, 0);
+ ++i;
+ if (errno != 0 || mode > 3) {
+ printf("Couldn't process mode\n");
+ return 1;
+ }
+ msg.mode &= ~(SPI_CPOL | SPI_CPHA);
+ msg.mode |= mode;
+ break;
+ case ('s'):
+ errno = 0;
+ msg.speed_hz = (uint32_t) strtoul(argv[i+1], NULL, 0);
+ ++i;
+ if (errno != 0) {
+ printf("Couldn't process speed\n");
+ return 1;
+ }
+ break;
+ case ('l'):
+ msg.mode |= SPI_LSB_FIRST;
+ break;
+ case ('o'):
+ msg.mode |= SPI_LOOP;
+ break;
+ case ('h'):
+ /* fallthrough */
+ default:
+ printf(rtems_spi_shell_usage);
+ return 1;
+ }
+ } else if (bus == NULL) {
+ bus = argv[i];
+ } else {
+ errno = 0;
+ buffer[len] = (uint8_t) strtol(argv[i], NULL, 16);
+ if (errno != 0) {
+ printf("Couldn't process '%s'\n", argv[i]);
+ return 1;
+ }
+ ++len;
+ }
+ }
+
+ if (len == 0) {
+ printf("Nothing to do\n");
+ return 0;
+ }
+
+ fd = open(bus, O_RDWR);
+ if (fd < 0) {
+ perror("Couldn't open bus");
+ return 1;
+ }
+ msg.len = len;
+ rv = ioctl(fd, SPI_IOC_MESSAGE(1), &msg);
+ if (rv == -1) {
+ perror("Couldn't send the message");
+ } else {
+ printf("received:");
+ for (j = 0; j < len; ++j) {
+ printf(" %02x", buffer[j]);
+ }
+ printf("\n");
+ }
+ close(fd);
+
+ return 0;
+}
+
+rtems_shell_cmd_t rtems_shell_SPI_Command = {
+ .name = "spi",
+ .usage = rtems_spi_shell_usage,
+ .topic = "misc",
+ .command = rtems_spi_shell_main,
+};
diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index a2f09fb99f..8888ab2c57 100644
--- a/cpukit/libmisc/untar/untar.c
+++ b/cpukit/libmisc/untar/untar.c
@@ -126,30 +126,25 @@ Make_Path(const rtems_printer *printer, char *path)
*p = '\0';
if (p[1] == '\0') {
- /* Speculatively unlink the last component so that it can be re-created */
- unlink(path);
return 0;
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- if (errno == EEXIST || errno == EISDIR) {
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
struct stat sb;
-
- if (stat(path, &sb) != 0) {
+ if (lstat(path, &sb) != 0) {
+ Print_Error(printer, "lstat", path);
+ return -1;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ path);
return -1;
}
-
- if (!S_ISDIR(sb.st_mode)) {
- if (unlink(path) != 0) {
- Print_Error(printer, "unlink", path);
- return -1;
- }
-
- if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- Print_Error(printer, "mkdir (unlink)", path);
- return -1;
- }
- }
+ } else {
+ Print_Error(printer, "mkdir", path);
+ return -1;
}
}
@@ -206,6 +201,12 @@ Untar_ProcessHeader(
if (Make_Path(ctx->printer, ctx->file_path) != 0) {
retval = UNTAR_FAIL;
+ } else {
+ /*
+ * Speculatively unlink. This should unlink everything but non-empty
+ * directories or write protected stuff.
+ */
+ unlink(ctx->file_path);
}
if (ctx->linkflag == SYMTYPE) {
@@ -225,8 +226,22 @@ Untar_ProcessHeader(
rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path);
r = mkdir(ctx->file_path, ctx->mode);
if (r != 0) {
- Print_Error(ctx->printer, "mkdir", ctx->file_path);
- retval = UNTAR_FAIL;
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
+ struct stat sb;
+ if (lstat(ctx->file_path, &sb) != 0) {
+ Print_Error(ctx->printer, "lstat", ctx->file_path);
+ retval = UNTAR_FAIL;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(ctx->printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
+ } else {
+ Print_Error(ctx->printer, "mkdir", ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
}
}
@@ -426,7 +441,9 @@ Untar_FromFile_Print(
*/
if ((out_fd = creat(ctx.file_path, ctx.mode)) == -1) {
- (void) lseek(fd, SEEK_CUR, 512UL * ctx.nblocks);
+ /* Couldn't create that file. Abort. */
+ retval = UNTAR_FAIL;
+ break;
} else {
for (i = 0; i < ctx.nblocks; i++) {
n = read(fd, bufr, 512);
diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c
index 8d1a4b84e4..792d222e2b 100644
--- a/cpukit/posix/src/nanosleep.c
+++ b/cpukit/posix/src/nanosleep.c
@@ -64,7 +64,7 @@ int clock_nanosleep(
)
{
Thread_queue_Context queue_context;
- struct timespec uptime;
+ struct timespec now;
const struct timespec *end;
Thread_Control *executing;
int eno;
@@ -81,21 +81,22 @@ int clock_nanosleep(
if ( ( flags & TIMER_ABSTIME ) != 0 ) {
end = rqtp;
-
+ } else {
if ( clock_id == CLOCK_REALTIME ) {
- _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
- &queue_context,
- end
- );
+ _Timecounter_Nanotime( &now );
} else {
- _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
- &queue_context,
- end
- );
+ _Timecounter_Nanouptime( &now );
}
+
+ end = _Watchdog_Future_timespec( &now, rqtp );
+ }
+
+ if ( clock_id == CLOCK_REALTIME ) {
+ _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
+ &queue_context,
+ end
+ );
} else {
- _Timecounter_Nanouptime( &uptime );
- end = _Watchdog_Future_timespec( &uptime, rqtp );
_Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
&queue_context,
end
@@ -120,7 +121,11 @@ int clock_nanosleep(
if ( eno == EINTR ) {
struct timespec actual_end;
- _Timecounter_Nanouptime( &actual_end );
+ if ( clock_id == CLOCK_REALTIME ) {
+ _Timecounter_Nanotime( &actual_end );
+ } else {
+ _Timecounter_Nanouptime( &actual_end );
+ }
if ( _Timespec_Less_than( &actual_end, end ) ) {
_Timespec_Subtract( &actual_end, end, rmtp );
diff --git a/cpukit/rtems/src/ratemoncreate.c b/cpukit/rtems/src/ratemoncreate.c
index 3eff5f0716..2e6b434d9e 100644
--- a/cpukit/rtems/src/ratemoncreate.c
+++ b/cpukit/rtems/src/ratemoncreate.c
@@ -53,6 +53,7 @@ rtems_status_code rtems_rate_monotonic_create(
the_period->owner = _Thread_Get_executing();
the_period->state = RATE_MONOTONIC_INACTIVE;
+ the_period->postponed_jobs = 0;
_Watchdog_Preinitialize( &the_period->Timer, _Per_CPU_Get_by_index( 0 ) );
_Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout );
diff --git a/cpukit/rtems/src/semcreate.c b/cpukit/rtems/src/semcreate.c
index b57b635d85..ea89800685 100644
--- a/cpukit/rtems/src/semcreate.c
+++ b/cpukit/rtems/src/semcreate.c
@@ -92,9 +92,14 @@ rtems_status_code rtems_semaphore_create(
) {
variant = SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING;
} else if (
- mutex_with_protocol
+ ( mutex_with_protocol & ~RTEMS_PRIORITY )
== ( RTEMS_BINARY_SEMAPHORE | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING )
) {
+ /*
+ * In RTEMS 5.2 using RTEMS_FIFO and RTEMS_PRIORITY for MrsP semaphores is
+ * allowed. In RTEMS 6, RTEMS_PRIORITY is required for MrsP semaphores
+ * analogous to priority ceiling semaphores.
+ */
#if defined(RTEMS_SMP)
variant = SEMAPHORE_VARIANT_MRSP;
#else
diff --git a/cpukit/rtems/src/taskstart.c b/cpukit/rtems/src/taskstart.c
index 247756fcb1..08bdfe8027 100644
--- a/cpukit/rtems/src/taskstart.c
+++ b/cpukit/rtems/src/taskstart.c
@@ -41,6 +41,10 @@ rtems_status_code rtems_task_start(
ISR_lock_Context lock_context;
bool ok;
+ if ( entry_point == NULL ) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
the_thread = _Thread_Get( id, &lock_context );
if ( the_thread == NULL ) {
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index d5afd5f7b0..1251faa2f7 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -523,8 +523,9 @@ dont_do_the_window:
* context.
*/
andcc %l0, %l5, %g0
- bne,a dont_switch_stacks
- st %fsr, [%g6 + SPARC_PER_CPU_FSR_OFFSET]
+ beq dont_switch_stacks
+ nop
+ st %fsr, [%g6 + SPARC_PER_CPU_FSR_OFFSET]
#endif
dont_switch_stacks:
@@ -683,11 +684,13 @@ isr_dispatch:
cmp %l6, %l7
bne,a .Ldisable_fp
andn %l0, %l5, %l0
+ st %g0, [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET]
ba .Lthread_dispatch_done
- st %g0, [%g6 + SPARC_PER_CPU_FP_OWNER_OFFSET]
+ nop
.Ldisable_fp:
+ st %l0, [%fp + ISF_PSR_OFFSET]
ba .Lthread_dispatch_done
- st %l0, [%fp + ISF_PSR_OFFSET]
+ nop
.Lnon_fp_thread_dispatch:
#elif defined(SPARC_USE_SYNCHRONOUS_FP_SWITCH)
/* Test if we interrupted a floating point thread (PSR[EF] == 1) */
diff --git a/cpukit/score/cpu/sparc/sparc-access.S b/cpukit/score/cpu/sparc/sparc-access.S
index 9397cb815b..277fb7e652 100644
--- a/cpukit/score/cpu/sparc/sparc-access.S
+++ b/cpukit/score/cpu/sparc/sparc-access.S
@@ -80,7 +80,9 @@ SYM(_st32):
SYM(_st_be64):
SYM(_st64):
- std %o1, [%o0]
+ mov %o2, %o3
+ mov %o1, %o2
+ std %o2, [%o0]
retl
nop
diff --git a/cpukit/score/cpu/sparc/sparc-counter-asm.S b/cpukit/score/cpu/sparc/sparc-counter-asm.S
index a1e18ae5b7..fb7783e096 100644
--- a/cpukit/score/cpu/sparc/sparc-counter-asm.S
+++ b/cpukit/score/cpu/sparc/sparc-counter-asm.S
@@ -31,8 +31,9 @@ SYM(_SPARC_Counter_read_default):
sethi %hi(_SPARC_Counter + 12), %o1
ld [%o1 + %lo(_SPARC_Counter + 12)], %o0
add %o0, 1, %o0
+ st %o0, [%o1 + %lo(_SPARC_Counter + 12)]
jmp %o7 + 8
- st %o0, [%o1 + %lo(_SPARC_Counter + 12)]
+ nop
PUBLIC(_SPARC_Counter_read_up)
PUBLIC(_SPARC_Get_timecount_up)
diff --git a/cpukit/score/cpu/sparc/syscall.S b/cpukit/score/cpu/sparc/syscall.S
index 4f4ef32c53..737a501098 100644
--- a/cpukit/score/cpu/sparc/syscall.S
+++ b/cpukit/score/cpu/sparc/syscall.S
@@ -218,9 +218,10 @@ SYM(syscall_lazy_fp_switch):
.Lfp_save_done:
/* Restore the floating point context if necessary */
+ st %g0, [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
cmp %l6, 0
be .Lfp_restore_done
- st %g0, [%l4 + %lo(SPARC_THREAD_CONTROL_REGISTERS_FP_CONTEXT_OFFSET)]
+ nop
ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F0_F1], %f0
ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F2_F3], %f2
ldd [%l6 + SPARC_FP_CONTEXT_OFFSET_F4_F5], %f4
diff --git a/cpukit/score/src/corebarrierrelease.c b/cpukit/score/src/corebarrierrelease.c
index a2e68862b3..da8da0a7d5 100644
--- a/cpukit/score/src/corebarrierrelease.c
+++ b/cpukit/score/src/corebarrierrelease.c
@@ -27,10 +27,9 @@ uint32_t _CORE_barrier_Do_flush(
Thread_queue_Context *queue_context
)
{
- the_barrier->number_of_waiting_threads = 0;
return _Thread_queue_Flush_critical(
&the_barrier->Wait_queue.Queue,
- CORE_BARRIER_TQ_OPERATIONS,
+ &_CORE_barrier_Thread_queue_operations,
filter,
queue_context
);
diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c
index f45873ccb8..2c59460c69 100644
--- a/cpukit/score/src/corebarrierwait.c
+++ b/cpukit/score/src/corebarrierwait.c
@@ -21,6 +21,36 @@
#include <rtems/score/corebarrierimpl.h>
#include <rtems/score/statesimpl.h>
#include <rtems/score/threadimpl.h>
+#include <rtems/score/threadqops.h>
+
+static void _CORE_barrier_Thread_queue_extract(
+ Thread_queue_Queue *queue,
+ Thread_Control *the_thread,
+ Thread_queue_Context *queue_context
+)
+{
+ CORE_barrier_Control *the_barrier;
+
+ the_barrier = RTEMS_CONTAINER_OF(
+ queue,
+ CORE_barrier_Control,
+ Wait_queue.Queue
+ );
+ --the_barrier->number_of_waiting_threads;
+ _Thread_queue_FIFO_extract(
+ &the_barrier->Wait_queue.Queue,
+ the_thread,
+ queue_context
+ );
+}
+
+const Thread_queue_Operations _CORE_barrier_Thread_queue_operations = {
+ .priority_actions = _Thread_queue_Do_nothing_priority_actions,
+ .enqueue = _Thread_queue_FIFO_enqueue,
+ .extract = _CORE_barrier_Thread_queue_extract,
+ .surrender = _Thread_queue_FIFO_surrender,
+ .first = _Thread_queue_FIFO_first
+};
Status_Control _CORE_barrier_Seize(
CORE_barrier_Control *the_barrier,
@@ -50,7 +80,7 @@ Status_Control _CORE_barrier_Seize(
);
_Thread_queue_Enqueue(
&the_barrier->Wait_queue.Queue,
- CORE_BARRIER_TQ_OPERATIONS,
+ &_CORE_barrier_Thread_queue_operations,
executing,
queue_context
);
diff --git a/cpukit/score/src/heapallocate.c b/cpukit/score/src/heapallocate.c
index 4b8b3f0de6..1c71e4a037 100644
--- a/cpukit/score/src/heapallocate.c
+++ b/cpukit/score/src/heapallocate.c
@@ -73,6 +73,15 @@
return search_again;
}
+
+ void _Heap_Protection_free_all_delayed_blocks( Heap_Control *heap )
+ {
+ bool search_again;
+
+ do {
+ search_again = _Heap_Protection_free_delayed_blocks( heap, 0 );
+ } while ( search_again );
+ }
#endif
#ifdef RTEMS_HEAP_DEBUG
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 1b65cf41ee..56ec4751ce 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: Beerware
+ *
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
@@ -7,7 +9,6 @@
* ----------------------------------------------------------------------------
*
* Copyright (c) 2011, 2015, 2016 The FreeBSD Foundation
- * All rights reserved.
*
* Portions of this software were developed by Julien Ridoux at the University
* of Melbourne under sponsorship from the FreeBSD Foundation.
@@ -44,9 +45,8 @@
#include <rtems/score/watchdogimpl.h>
#endif /* __rtems__ */
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/kern/kern_tc.c 324528 2017-10-11 11:03:11Z kib $");
+__FBSDID("$FreeBSD$");
-#include "opt_compat.h"
#include "opt_ntp.h"
#include "opt_ffclock.h"
@@ -79,16 +79,7 @@ ISR_LOCK_DEFINE(, _Timecounter_Lock, "Timecounter")
_ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, lock_context)
#define hz rtems_clock_get_ticks_per_second()
#define printf(...)
-#define bcopy(x, y, z) memcpy(y, x, z);
#define log(...)
-static inline int
-builtin_fls(int x)
-{
- return x ? sizeof(x) * 8 - __builtin_clz(x) : 0;
-}
-#define fls(x) builtin_fls(x)
-/* FIXME: https://devel.rtems.org/ticket/2348 */
-#define ntp_update_second(a, b) do { (void) a; (void) b; } while (0)
static inline void
atomic_thread_fence_acq(void)
@@ -117,6 +108,24 @@ atomic_store_rel_int(Atomic_Uint *i, u_int val)
_Atomic_Store_uint(i, val, ATOMIC_ORDER_RELEASE);
}
+
+static inline void *
+atomic_load_ptr(void *ptr)
+{
+
+ return ((void *)_Atomic_Load_uintptr(ptr, ATOMIC_ORDER_RELAXED));
+}
+
+static Timecounter_NTP_update_second _Timecounter_NTP_update_second;
+
+void
+_Timecounter_Set_NTP_update_second(Timecounter_NTP_update_second handler)
+{
+
+ _Timecounter_NTP_update_second = handler;
+}
+
+#define ntp_update_second(a, b) (*ntp_update_second_handler)(a, b)
#endif /* __rtems__ */
/*
@@ -158,6 +167,7 @@ struct timehands {
struct timecounter *th_counter;
int64_t th_adjustment;
uint64_t th_scale;
+ uint32_t th_large_delta;
uint32_t th_offset_count;
struct bintime th_offset;
struct bintime th_bintime;
@@ -173,6 +183,40 @@ struct timehands {
struct timehands *th_next;
};
+#ifndef __rtems__
+static struct timehands ths[16] = {
+ [0] = {
+ .th_counter = &dummy_timecounter,
+ .th_scale = (uint64_t)-1 / 1000000,
+ .th_large_delta = 1000000,
+ .th_offset = { .sec = 1 },
+ .th_generation = 1,
+ },
+};
+
+static struct timehands *volatile timehands = &ths[0];
+struct timecounter *timecounter = &dummy_timecounter;
+static struct timecounter *timecounters = &dummy_timecounter;
+
+/* Mutex to protect the timecounter list. */
+static struct mtx tc_lock;
+MTX_SYSINIT(tc_lock, &tc_lock, "tc", MTX_DEF);
+
+int tc_min_ticktock_freq = 1;
+#else /* __rtems__ */
+/*
+ * In FreeBSD, the timehands count is a tuning option from two to 16. The
+ * tuning option was added since it is inexpensive and some FreeBSD users asked
+ * for it to play around. The default value is two. One system which did not
+ * work with two timehands was a system with one processor and a specific PPS
+ * device.
+ *
+ * For RTEMS, in uniprocessor configurations, just use one timehand since the
+ * update is done with interrupt disabled.
+ *
+ * In SMP configurations, use a fixed set of two timehands until someone
+ * reports an issue.
+ */
#if defined(RTEMS_SMP)
static struct timehands th0;
static struct timehands th1 = {
@@ -183,7 +227,8 @@ static struct timehands th0 = {
.th_counter = &dummy_timecounter,
.th_scale = (uint64_t)-1 / 1000000,
.th_offset = { .sec = 1 },
- .th_generation = 1,
+ .th_large_delta = 1000000,
+ .th_generation = UINT_MAX,
#ifdef __rtems__
.th_bintime = { .sec = TOD_SECONDS_1970_THROUGH_1988 },
.th_microtime = { TOD_SECONDS_1970_THROUGH_1988, 0 },
@@ -199,10 +244,6 @@ static struct timehands th0 = {
static struct timehands *volatile timehands = &th0;
struct timecounter *timecounter = &dummy_timecounter;
-#ifndef __rtems__
-static struct timecounter *timecounters = &dummy_timecounter;
-
-int tc_min_ticktock_freq = 1;
#endif /* __rtems__ */
#ifndef __rtems__
@@ -214,17 +255,33 @@ volatile int32_t time_uptime = 1;
#endif /* __rtems__ */
#ifndef __rtems__
+/*
+ * The system time is always computed by summing the estimated boot time and the
+ * system uptime. The timehands track boot time, but it changes when the system
+ * time is set by the user, stepped by ntpd or adjusted when resuming. It
+ * is set to new_time - uptime.
+ */
static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
-SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
- NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
+SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime,
+ CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_kern_boottime, "S,timeval",
+ "Estimated system boottime");
-SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
-static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, CTLFLAG_RW, 0, "");
+SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "");
+static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc,
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "");
static int timestepwarnings;
-SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW,
+SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RWTUN,
&timestepwarnings, 0, "Log time steps");
+static int timehands_count = 2;
+SYSCTL_INT(_kern_timecounter, OID_AUTO, timehands_count,
+ CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &timehands_count, 0, "Count of timehands in rotation");
+
struct bintime bt_timethreshold;
struct bintime bt_tickthreshold;
sbintime_t sbt_timethreshold;
@@ -242,6 +299,7 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation,
volatile int rtc_generation = 1;
static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */
+static char tc_from_tunable[16];
#endif /* __rtems__ */
static void tc_windup(struct bintime *new_boottimebin);
@@ -253,6 +311,7 @@ static void _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
void dtrace_getnanotime(struct timespec *tsp);
+void dtrace_getnanouptime(struct timespec *tsp);
#ifndef __rtems__
static int
@@ -262,7 +321,8 @@ sysctl_kern_boottime(SYSCTL_HANDLER_ARGS)
getboottime(&boottime);
-#ifndef __mips__
+/* i386 is the only arch which uses a 32bits time_t */
+#ifdef __amd64__
#ifdef SCTL_MASK32
int tv[2];
@@ -317,20 +377,85 @@ tc_delta(struct timehands *th)
* the comment in <sys/time.h> for a description of these 12 functions.
*/
-#ifdef FFCLOCK
-void
-fbclock_binuptime(struct bintime *bt)
+static __inline void
+bintime_off(struct bintime *bt, u_int off)
{
struct timehands *th;
- unsigned int gen;
+ struct bintime *btp;
+ uint64_t scale, x;
+#ifndef __rtems__
+ u_int delta, gen, large_delta;
+#else /* __rtems__ */
+ uint32_t delta, large_delta;
+ u_int gen;
+#endif /* __rtems__ */
do {
th = timehands;
gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- bintime_addx(bt, th->th_scale * tc_delta(th));
+ btp = (struct bintime *)((vm_offset_t)th + off);
+ *bt = *btp;
+ scale = th->th_scale;
+ delta = tc_delta(th);
+ large_delta = th->th_large_delta;
atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
} while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+
+ if (__predict_false(delta >= large_delta)) {
+ /* Avoid overflow for scale * delta. */
+ x = (scale >> 32) * delta;
+ bt->sec += x >> 32;
+ bintime_addx(bt, x << 32);
+ bintime_addx(bt, (scale & 0xffffffff) * delta);
+ } else {
+ bintime_addx(bt, scale * delta);
+ }
+}
+#define GETTHBINTIME(dst, member) \
+do { \
+ _Static_assert(_Generic(((struct timehands *)NULL)->member, \
+ struct bintime: 1, default: 0) == 1, \
+ "struct timehands member is not of struct bintime type"); \
+ bintime_off(dst, __offsetof(struct timehands, member)); \
+} while (0)
+
+static __inline void
+getthmember(void *out, size_t out_size, u_int off)
+{
+ struct timehands *th;
+ u_int gen;
+
+ do {
+ th = timehands;
+ gen = atomic_load_acq_int(&th->th_generation);
+ memcpy(out, (char *)th + off, out_size);
+ atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
+ } while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+}
+#define GETTHMEMBER(dst, member) \
+do { \
+ _Static_assert(_Generic(*dst, \
+ __typeof(((struct timehands *)NULL)->member): 1, \
+ default: 0) == 1, \
+ "*dst and struct timehands member have different types"); \
+ getthmember(dst, sizeof(*dst), __offsetof(struct timehands, \
+ member)); \
+} while (0)
+
+#ifdef FFCLOCK
+void
+fbclock_binuptime(struct bintime *bt)
+{
+
+ GETTHBINTIME(bt, th_offset);
}
void
@@ -354,16 +479,8 @@ fbclock_microuptime(struct timeval *tvp)
void
fbclock_bintime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_bintime);
}
void
@@ -387,116 +504,88 @@ fbclock_microtime(struct timeval *tvp)
void
fbclock_getbinuptime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_offset);
}
void
fbclock_getnanouptime(struct timespec *tsp)
{
- struct timehands *th;
- unsigned int gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timespec(&th->th_offset, tsp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
void
fbclock_getmicrouptime(struct timeval *tvp)
{
- struct timehands *th;
- unsigned int gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timeval(&th->th_offset, tvp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timeval(&bt, tvp);
}
void
fbclock_getbintime(struct bintime *bt)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_bintime);
}
void
fbclock_getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
}
void
fbclock_getmicrotime(struct timeval *tvp)
{
- struct timehands *th;
- unsigned int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tvp = th->th_microtime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tvp, th_microtime);
}
#else /* !FFCLOCK */
+
void
binuptime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_offset);
}
#ifdef __rtems__
sbintime_t
_Timecounter_Sbinuptime(void)
{
struct timehands *th;
- uint32_t gen;
sbintime_t sbt;
+ uint64_t scale;
+ uint32_t delta;
+ uint32_t large_delta;
+ u_int gen;
do {
th = timehands;
gen = atomic_load_acq_int(&th->th_generation);
sbt = bttosbt(th->th_offset);
- sbt += (th->th_scale * tc_delta(th)) >> 32;
+ scale = th->th_scale;
+ delta = tc_delta(th);
+ large_delta = th->th_large_delta;
atomic_thread_fence_acq();
+#if defined(RTEMS_SMP)
} while (gen == 0 || gen != th->th_generation);
+#else
+ } while (gen != th->th_generation);
+#endif
+
+ if (__predict_false(delta >= large_delta)) {
+ /* Avoid overflow for scale * delta. */
+ sbt += (scale >> 32) * delta;
+ sbt += ((scale & 0xffffffff) * delta) >> 32;
+ } else {
+ sbt += (scale * delta) >> 32;
+ }
return (sbt);
}
@@ -523,16 +612,8 @@ microuptime(struct timeval *tvp)
void
bintime(struct bintime *bt)
{
- struct timehands *th;
- u_int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHBINTIME(bt, th_bintime);
}
void
@@ -556,85 +637,47 @@ microtime(struct timeval *tvp)
void
getbinuptime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_offset;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_offset);
}
void
getnanouptime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timespec(&th->th_offset, tsp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
void
getmicrouptime(struct timeval *tvp)
{
- struct timehands *th;
- uint32_t gen;
+ struct bintime bt;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- bintime2timeval(&th->th_offset, tvp);
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timeval(&bt, tvp);
}
void
getbintime(struct bintime *bt)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *bt = th->th_bintime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(bt, th_bintime);
}
void
getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
}
void
getmicrotime(struct timeval *tvp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tvp = th->th_microtime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tvp, th_microtime);
}
#endif /* FFCLOCK */
@@ -650,15 +693,8 @@ getboottime(struct timeval *boottime)
void
getboottimebin(struct bintime *boottimebin)
{
- struct timehands *th;
- u_int gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *boottimebin = th->th_boottime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(boottimebin, th_boottime);
}
#ifdef FFCLOCK
@@ -1175,15 +1211,22 @@ getmicrotime(struct timeval *tvp)
void
dtrace_getnanotime(struct timespec *tsp)
{
- struct timehands *th;
- uint32_t gen;
- do {
- th = timehands;
- gen = atomic_load_acq_int(&th->th_generation);
- *tsp = th->th_nanotime;
- atomic_thread_fence_acq();
- } while (gen == 0 || gen != th->th_generation);
+ GETTHMEMBER(tsp, th_nanotime);
+}
+
+/*
+ * This is a clone of getnanouptime used for time since boot.
+ * The dtrace_ prefix prevents fbt from creating probes for
+ * it so an uptime that can be safely used in all fbt probes.
+ */
+void
+dtrace_getnanouptime(struct timespec *tsp)
+{
+ struct bintime bt;
+
+ GETTHMEMBER(&bt, th_offset);
+ bintime2timespec(&bt, tsp);
}
#endif /* __rtems__ */
@@ -1364,26 +1407,32 @@ tc_init(struct timecounter *tc)
tc->tc_quality);
}
- tc->tc_next = timecounters;
- timecounters = tc;
/*
* Set up sysctl tree for this counter.
*/
tc_root = SYSCTL_ADD_NODE_WITH_LABEL(NULL,
SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name,
- CTLFLAG_RW, 0, "timecounter description", "timecounter");
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+ "timecounter description", "timecounter");
SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
"mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0,
"mask for implemented bits");
SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "counter", CTLTYPE_UINT | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_get, "IU", "current timecounter value");
+ "counter", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, tc,
+ sizeof(*tc), sysctl_kern_timecounter_get, "IU",
+ "current timecounter value");
SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "frequency", CTLTYPE_U64 | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_freq, "QU", "timecounter frequency");
+ "frequency", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE, tc,
+ sizeof(*tc), sysctl_kern_timecounter_freq, "QU",
+ "timecounter frequency");
SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
"quality", CTLFLAG_RD, &(tc->tc_quality), 0,
"goodness of time counter");
+
+ mtx_lock(&tc_lock);
+ tc->tc_next = timecounters;
+ timecounters = tc;
+
/*
* Do not automatically switch if the current tc was specifically
* chosen. Never automatically use a timecounter with negative quality.
@@ -1391,21 +1440,31 @@ tc_init(struct timecounter *tc)
* worse since this timecounter may not be monotonic.
*/
if (tc_chosen)
- return;
+ goto unlock;
if (tc->tc_quality < 0)
- return;
-#endif /* __rtems__ */
+ goto unlock;
+ if (tc_from_tunable[0] != '\0' &&
+ strcmp(tc->tc_name, tc_from_tunable) == 0) {
+ tc_chosen = 1;
+ tc_from_tunable[0] = '\0';
+ } else {
+ if (tc->tc_quality < timecounter->tc_quality)
+ goto unlock;
+ if (tc->tc_quality == timecounter->tc_quality &&
+ tc->tc_frequency < timecounter->tc_frequency)
+ goto unlock;
+ }
+ (void)tc->tc_get_timecount(tc);
+ timecounter = tc;
+unlock:
+ mtx_unlock(&tc_lock);
+#else /* __rtems__ */
if (tc->tc_quality < timecounter->tc_quality)
return;
if (tc->tc_quality == timecounter->tc_quality &&
tc->tc_frequency < timecounter->tc_frequency)
return;
-#ifndef __rtems__
- (void)tc->tc_get_timecount(tc);
- (void)tc->tc_get_timecount(tc);
-#endif /* __rtems__ */
timecounter = tc;
-#ifdef __rtems__
tc_windup(NULL);
#endif /* __rtems__ */
}
@@ -1493,6 +1552,40 @@ _Timecounter_Set_clock(const struct bintime *_bt,
}
/*
+ * Recalculate the scaling factor. We want the number of 1/2^64
+ * fractions of a second per period of the hardware counter, taking
+ * into account the th_adjustment factor which the NTP PLL/adjtime(2)
+ * processing provides us with.
+ *
+ * The th_adjustment is nanoseconds per second with 32 bit binary
+ * fraction and we want 64 bit binary fraction of second:
+ *
+ * x = a * 2^32 / 10^9 = a * 4.294967296
+ *
+ * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
+ * we can only multiply by about 850 without overflowing, that
+ * leaves no suitably precise fractions for multiply before divide.
+ *
+ * Divide before multiply with a fraction of 2199/512 results in a
+ * systematic undercompensation of 10PPM of th_adjustment. On a
+ * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
+ *
+ * We happily sacrifice the lowest of the 64 bits of our result
+ * to the goddess of code clarity.
+ */
+static void
+recalculate_scaling_factor_and_large_delta(struct timehands *th)
+{
+ uint64_t scale;
+
+ scale = (uint64_t)1 << 63;
+ scale += (th->th_adjustment / 1024) * 2199;
+ scale /= th->th_counter->tc_frequency;
+ th->th_scale = scale * 2;
+ th->th_large_delta = MIN(((uint64_t)1 << 63) / scale, UINT_MAX);
+}
+
+/*
* Initialize the next struct timehands in the ring and make
* it the active timehands. Along the way we might switch to a different
* timecounter and/or do seconds processing in NTP. Slightly magic.
@@ -1513,11 +1606,17 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
{
struct bintime bt;
+ struct timecounter *tc;
struct timehands *th, *tho;
- uint64_t scale;
- uint32_t delta, ncount, ogen;
+ uint32_t delta, ncount;
+#if defined(RTEMS_SMP)
+ u_int ogen;
+#endif
int i;
time_t t;
+#ifdef __rtems__
+ Timecounter_NTP_update_second ntp_update_second_handler;
+#endif
/*
* Make the next timehands a copy of the current one, but do
@@ -1531,14 +1630,12 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
tho = timehands;
#if defined(RTEMS_SMP)
th = tho->th_next;
-#else
- th = tho;
-#endif
ogen = th->th_generation;
th->th_generation = 0;
atomic_thread_fence_rel();
-#if defined(RTEMS_SMP)
- bcopy(tho, th, offsetof(struct timehands, th_generation));
+ memcpy(th, tho, offsetof(struct timehands, th_generation));
+#else
+ th = tho;
#endif
if (new_boottimebin != NULL)
th->th_boottime = *new_boottimebin;
@@ -1548,9 +1645,10 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
* changing timecounters, a counter value from the new timecounter.
* Update the offset fields accordingly.
*/
+ tc = atomic_load_ptr(&timecounter);
delta = tc_delta(th);
- if (th->th_counter != timecounter)
- ncount = timecounter->tc_get_timecount(timecounter);
+ if (th->th_counter != tc)
+ ncount = tc->tc_get_timecount(tc);
else
ncount = 0;
#ifdef FFCLOCK
@@ -1584,7 +1682,7 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
#endif /* __rtems__ */
/*
- * Deal with NTP second processing. The for loop normally
+ * Deal with NTP second processing. The loop normally
* iterates at most once, but in extreme situations it might
* keep NTP sane if timeouts are not run for several seconds.
* At boot, the time step can be large when the TOD hardware
@@ -1594,69 +1692,57 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
*/
bt = th->th_offset;
bintime_add(&bt, &th->th_boottime);
+#ifdef __rtems__
+ ntp_update_second_handler = _Timecounter_NTP_update_second;
+ if (ntp_update_second_handler != NULL) {
+#endif /* __rtems__ */
i = bt.sec - tho->th_microtime.tv_sec;
- if (i > LARGE_STEP)
- i = 2;
- for (; i > 0; i--) {
- t = bt.sec;
- ntp_update_second(&th->th_adjustment, &bt.sec);
- if (bt.sec != t)
- th->th_boottime.sec += bt.sec - t;
+ if (i > 0) {
+ if (i > LARGE_STEP)
+ i = 2;
+
+ do {
+ t = bt.sec;
+ ntp_update_second(&th->th_adjustment, &bt.sec);
+ if (bt.sec != t)
+ th->th_boottime.sec += bt.sec - t;
+ --i;
+ } while (i > 0);
+
+ recalculate_scaling_factor_and_large_delta(th);
}
+#ifdef __rtems__
+ }
+#endif /* __rtems__ */
+
/* Update the UTC timestamps used by the get*() functions. */
th->th_bintime = bt;
bintime2timeval(&bt, &th->th_microtime);
bintime2timespec(&bt, &th->th_nanotime);
/* Now is a good time to change timecounters. */
- if (th->th_counter != timecounter) {
+ if (th->th_counter != tc) {
#ifndef __rtems__
#ifndef __arm__
- if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0)
+ if ((tc->tc_flags & TC_FLAGS_C2STOP) != 0)
cpu_disable_c2_sleep++;
if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0)
cpu_disable_c2_sleep--;
#endif
#endif /* __rtems__ */
- th->th_counter = timecounter;
+ th->th_counter = tc;
th->th_offset_count = ncount;
#ifndef __rtems__
- tc_min_ticktock_freq = max(1, timecounter->tc_frequency /
- (((uint64_t)timecounter->tc_counter_mask + 1) / 3));
+ tc_min_ticktock_freq = max(1, tc->tc_frequency /
+ (((uint64_t)tc->tc_counter_mask + 1) / 3));
#endif /* __rtems__ */
+ recalculate_scaling_factor_and_large_delta(th);
#ifdef FFCLOCK
ffclock_change_tc(th);
#endif
}
- /*-
- * Recalculate the scaling factor. We want the number of 1/2^64
- * fractions of a second per period of the hardware counter, taking
- * into account the th_adjustment factor which the NTP PLL/adjtime(2)
- * processing provides us with.
- *
- * The th_adjustment is nanoseconds per second with 32 bit binary
- * fraction and we want 64 bit binary fraction of second:
- *
- * x = a * 2^32 / 10^9 = a * 4.294967296
- *
- * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
- * we can only multiply by about 850 without overflowing, that
- * leaves no suitably precise fractions for multiply before divide.
- *
- * Divide before multiply with a fraction of 2199/512 results in a
- * systematic undercompensation of 10PPM of th_adjustment. On a
- * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
- *
- * We happily sacrifice the lowest of the 64 bits of our result
- * to the goddess of code clarity.
- *
- */
- scale = (uint64_t)1 << 63;
- scale += (th->th_adjustment / 1024) * 2199;
- scale /= th->th_counter->tc_frequency;
- th->th_scale = scale * 2;
-
+#if defined(RTEMS_SMP)
/*
* Now that the struct timehands is again consistent, set the new
* generation number, making sure to not make it zero.
@@ -1664,6 +1750,9 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
if (++ogen == 0)
ogen = 1;
atomic_store_rel_int(&th->th_generation, ogen);
+#else
+ atomic_store_rel_int(&th->th_generation, th->th_generation + 1);
+#endif
/* Go live with the new struct timehands. */
#ifdef FFCLOCK
@@ -1701,23 +1790,28 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
struct timecounter *newtc, *tc;
int error;
+ mtx_lock(&tc_lock);
tc = timecounter;
strlcpy(newname, tc->tc_name, sizeof(newname));
+ mtx_unlock(&tc_lock);
error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
if (error != 0 || req->newptr == NULL)
return (error);
+
+ mtx_lock(&tc_lock);
/* Record that the tc in use now was specifically chosen. */
tc_chosen = 1;
- if (strcmp(newname, tc->tc_name) == 0)
+ if (strcmp(newname, tc->tc_name) == 0) {
+ mtx_unlock(&tc_lock);
return (0);
+ }
for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
if (strcmp(newname, newtc->tc_name) != 0)
continue;
/* Warm up new timecounter. */
(void)newtc->tc_get_timecount(newtc);
- (void)newtc->tc_get_timecount(newtc);
timecounter = newtc;
@@ -1729,16 +1823,16 @@ sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
* use any locking and that it can be called in hard interrupt
* context via 'tc_windup()'.
*/
- return (0);
+ break;
}
- return (EINVAL);
+ mtx_unlock(&tc_lock);
+ return (newtc != NULL ? 0 : EINVAL);
}
-
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
- 0, 0, sysctl_kern_timecounter_hardware, "A",
+SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware,
+ CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE, 0, 0,
+ sysctl_kern_timecounter_hardware, "A",
"Timecounter hardware selected");
-
/* Report the available timecounter hardware. */
static int
sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
@@ -1747,19 +1841,26 @@ sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
struct timecounter *tc;
int error;
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error != 0)
+ return (error);
sbuf_new_for_sysctl(&sb, NULL, 0, req);
+ mtx_lock(&tc_lock);
for (tc = timecounters; tc != NULL; tc = tc->tc_next) {
if (tc != timecounters)
sbuf_putc(&sb, ' ');
sbuf_printf(&sb, "%s(%d)", tc->tc_name, tc->tc_quality);
}
+ mtx_unlock(&tc_lock);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
return (error);
}
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
- 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected");
+SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice,
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,
+ sysctl_kern_timecounter_choice, "A",
+ "Timecounter hardware detected");
#endif /* __rtems__ */
#ifndef __rtems__
@@ -1803,10 +1904,10 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps)
tv.tv_usec = fapi->timeout.tv_nsec / 1000;
timo = tvtohz(&tv);
}
- aseq = pps->ppsinfo.assert_sequence;
- cseq = pps->ppsinfo.clear_sequence;
- while (aseq == pps->ppsinfo.assert_sequence &&
- cseq == pps->ppsinfo.clear_sequence) {
+ aseq = atomic_load_int(&pps->ppsinfo.assert_sequence);
+ cseq = atomic_load_int(&pps->ppsinfo.clear_sequence);
+ while (aseq == atomic_load_int(&pps->ppsinfo.assert_sequence) &&
+ cseq == atomic_load_int(&pps->ppsinfo.clear_sequence)) {
if (abi_aware(pps, 1) && pps->driver_mtx != NULL) {
if (pps->flags & PPSFLAG_MTX_SPIN) {
err = msleep_spin(pps, pps->driver_mtx,
@@ -2144,27 +2245,38 @@ _Timecounter_Tick_simple(uint32_t delta, uint32_t offset,
{
struct bintime bt;
struct timehands *th;
- uint32_t ogen;
+#if defined(RTEMS_SMP)
+ u_int ogen;
+#endif
th = timehands;
+#if defined(RTEMS_SMP)
ogen = th->th_generation;
+ th->th_generation = 0;
+ atomic_thread_fence_rel();
+#endif
+
th->th_offset_count = offset;
bintime_addx(&th->th_offset, th->th_scale * delta);
-
bt = th->th_offset;
bintime_add(&bt, &th->th_boottime);
+
/* Update the UTC timestamps used by the get*() functions. */
th->th_bintime = bt;
bintime2timeval(&bt, &th->th_microtime);
bintime2timespec(&bt, &th->th_nanotime);
+#if defined(RTEMS_SMP)
/*
* Now that the struct timehands is again consistent, set the new
* generation number, making sure to not make it zero.
*/
if (++ogen == 0)
ogen = 1;
- th->th_generation = ogen;
+ atomic_store_rel_int(&th->th_generation, ogen);
+#else
+ atomic_store_rel_int(&th->th_generation, th->th_generation + 1);
+#endif
/* Go live with the new struct timehands. */
time_second = th->th_microtime.tv_sec;
@@ -2218,6 +2330,28 @@ done:
return (0);
}
+/* Set up the requested number of timehands. */
+static void
+inittimehands(void *dummy)
+{
+ struct timehands *thp;
+ int i;
+
+ TUNABLE_INT_FETCH("kern.timecounter.timehands_count",
+ &timehands_count);
+ if (timehands_count < 1)
+ timehands_count = 1;
+ if (timehands_count > nitems(ths))
+ timehands_count = nitems(ths);
+ for (i = 1, thp = &ths[0]; i < timehands_count; thp = &ths[i++])
+ thp->th_next = &ths[i];
+ thp->th_next = &ths[0];
+
+ TUNABLE_STR_FETCH("kern.timecounter.hardware", tc_from_tunable,
+ sizeof(tc_from_tunable));
+}
+SYSINIT(timehands, SI_SUB_TUNABLES, SI_ORDER_ANY, inittimehands, NULL);
+
static void
inittimecounter(void *dummy)
{
@@ -2248,9 +2382,9 @@ inittimecounter(void *dummy)
#ifdef FFCLOCK
ffclock_init();
#endif
+
/* warm up new timecounter (again) and get rolling. */
(void)timecounter->tc_get_timecount(timecounter);
- (void)timecounter->tc_get_timecount(timecounter);
mtx_lock_spin(&tc_setclock_mtx);
tc_windup(NULL);
mtx_unlock_spin(&tc_setclock_mtx);
@@ -2263,8 +2397,8 @@ SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL);
static int cpu_tick_variable;
static uint64_t cpu_tick_frequency;
-static DPCPU_DEFINE(uint64_t, tc_cpu_ticks_base);
-static DPCPU_DEFINE(unsigned, tc_cpu_ticks_last);
+DPCPU_DEFINE_STATIC(uint64_t, tc_cpu_ticks_base);
+DPCPU_DEFINE_STATIC(unsigned, tc_cpu_ticks_last);
static uint64_t
tc_cpu_ticks(void)
@@ -2438,7 +2572,6 @@ tc_fill_vdso_timehands(struct vdso_timehands *vdso_th)
enabled = 0;
return (enabled);
}
-#endif /* __rtems__ */
#ifdef COMPAT_FREEBSD32
uint32_t
@@ -2465,3 +2598,34 @@ tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32)
return (enabled);
}
#endif
+
+#include "opt_ddb.h"
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(timecounter, db_show_timecounter)
+{
+ struct timehands *th;
+ struct timecounter *tc;
+ u_int val1, val2;
+
+ th = timehands;
+ tc = th->th_counter;
+ val1 = tc->tc_get_timecount(tc);
+ __compiler_membar();
+ val2 = tc->tc_get_timecount(tc);
+
+ db_printf("timecounter %p %s\n", tc, tc->tc_name);
+ db_printf(" mask %#x freq %ju qual %d flags %#x priv %p\n",
+ tc->tc_counter_mask, (uintmax_t)tc->tc_frequency, tc->tc_quality,
+ tc->tc_flags, tc->tc_priv);
+ db_printf(" val %#x %#x\n", val1, val2);
+ db_printf("timehands adj %#jx scale %#jx ldelta %d off_cnt %d gen %d\n",
+ (uintmax_t)th->th_adjustment, (uintmax_t)th->th_scale,
+ th->th_large_delta, th->th_offset_count, th->th_generation);
+ db_printf(" offset %jd %jd boottime %jd %jd\n",
+ (intmax_t)th->th_offset.sec, (uintmax_t)th->th_offset.frac,
+ (intmax_t)th->th_boottime.sec, (uintmax_t)th->th_boottime.frac);
+}
+#endif
+#endif /* __rtems__ */
diff --git a/cpukit/score/src/objectactivecount.c b/cpukit/score/src/objectactivecount.c
index c658fc21e3..12c15147c7 100644
--- a/cpukit/score/src/objectactivecount.c
+++ b/cpukit/score/src/objectactivecount.c
@@ -24,14 +24,22 @@ Objects_Maximum _Objects_Active_count(
const Objects_Information *information
)
{
- Objects_Maximum inactive;
- Objects_Maximum maximum;
+ Objects_Maximum active;
+ Objects_Maximum index;
+ Objects_Maximum maximum;
+ Objects_Control **local_table;
_Assert( _Objects_Allocator_is_owner() );
- inactive = (Objects_Maximum)
- _Chain_Node_count_unprotected( &information->Inactive );
+ active = 0;
maximum = _Objects_Get_maximum_index( information );
+ local_table = information->local_table;
- return maximum - inactive;
+ for ( index = 0; index < maximum; ++index ) {
+ if ( local_table[ index ] != NULL ) {
+ ++active;
+ }
+ }
+
+ return active;
}
diff --git a/cpukit/score/src/objectfree.c b/cpukit/score/src/objectfree.c
index 1f7aa37e3f..964adbc62a 100644
--- a/cpukit/score/src/objectfree.c
+++ b/cpukit/score/src/objectfree.c
@@ -30,14 +30,16 @@ void _Objects_Free_unlimited(
if ( _Objects_Is_auto_extend( information ) ) {
Objects_Maximum objects_per_block;
- Objects_Maximum block;
- Objects_Maximum inactive;
+ Objects_Maximum index;
objects_per_block = information->objects_per_block;
- block = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
+ index = _Objects_Get_index( the_object->id ) - OBJECTS_INDEX_MINIMUM;
- if ( block > objects_per_block ) {
- block /= objects_per_block;
+ if ( _Objects_Is_in_allocated_block( index, objects_per_block ) ) {
+ Objects_Maximum block;
+ Objects_Maximum inactive;
+
+ block = index / objects_per_block;
++information->inactive_per_block[ block ];
diff --git a/cpukit/score/src/stackallocatorforidle.c b/cpukit/score/src/stackallocatorforidle.c
new file mode 100644
index 0000000000..7c4fd10c7d
--- /dev/null
+++ b/cpukit/score/src/stackallocatorforidle.c
@@ -0,0 +1,59 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2021 OAR Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/stack.h>
+#include <rtems/score/thread.h>
+
+/**
+ * @brief Default stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * The default allocator for IDLE thread stacks gets the memory from a
+ * statically allocated area provided via confdefs.h.
+ *
+ * @param cpu Index of the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory (never returned).
+ * @retval other Pointer to begin of stack area.
+ */
+static void *_Stack_Allocator_allocate_for_idle_default(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ return &_Thread_Idle_stacks[ cpu * stack_size ];
+}
+
+const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ _Stack_Allocator_allocate_for_idle_default;
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index 1e18ad07cc..e888aa111f 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -53,9 +53,15 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
config.is_preemptible = true;
config.stack_size = _Thread_Idle_stack_size
+ CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE;
- config.stack_area = &_Thread_Idle_stacks[
- _Per_CPU_Get_index( cpu ) * config.stack_size
- ];
+
+ /*
+ * The IDLE thread stacks may be statically allocated or there may be a
+ * custom allocator provided just as with user threads.
+ */
+ config.stack_area = (*_Stack_Allocator_allocate_for_idle)(
+ _Per_CPU_Get_index( cpu ),
+ config.stack_size
+ );
/*
* The entire workspace is zeroed during its initialization. Thus, all
diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c
index 9894c3628b..8c3e0cb1dc 100644
--- a/cpukit/score/src/threadqops.c
+++ b/cpukit/score/src/threadqops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2015, 2021 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -16,6 +16,7 @@
#include "config.h"
#endif
+#include <rtems/score/threadqops.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/assert.h>
#include <rtems/score/chainimpl.h>
@@ -38,7 +39,7 @@
Queue \
)
-static void _Thread_queue_Do_nothing_priority_actions(
+void _Thread_queue_Do_nothing_priority_actions(
Thread_queue_Queue *queue,
Priority_Actions *priority_actions
)
@@ -187,7 +188,7 @@ static void _Thread_queue_FIFO_do_extract(
_Chain_Extract_unprotected( &scheduler_node->Wait.Priority.Node.Node.Chain );
}
-static void _Thread_queue_FIFO_enqueue(
+void _Thread_queue_FIFO_enqueue(
Thread_queue_Queue *queue,
Thread_Control *the_thread,
Thread_queue_Context *queue_context
@@ -202,7 +203,7 @@ static void _Thread_queue_FIFO_enqueue(
);
}
-static void _Thread_queue_FIFO_extract(
+void _Thread_queue_FIFO_extract(
Thread_queue_Queue *queue,
Thread_Control *the_thread,
Thread_queue_Context *queue_context
@@ -218,23 +219,21 @@ static void _Thread_queue_FIFO_extract(
);
}
-static Thread_Control *_Thread_queue_FIFO_first(
- Thread_queue_Heads *heads
-)
+Thread_Control *_Thread_queue_FIFO_first( const Thread_queue_Heads *heads )
{
- Chain_Control *fifo;
- Chain_Node *first;
- Scheduler_Node *scheduler_node;
+ const Chain_Control *fifo;
+ const Chain_Node *first;
+ const Scheduler_Node *scheduler_node;
fifo = &heads->Heads.Fifo;
_Assert( !_Chain_Is_empty( fifo ) );
- first = _Chain_First( fifo );
+ first = _Chain_Immutable_first( fifo );
scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
return _Scheduler_Node_get_owner( scheduler_node );
}
-static Thread_Control *_Thread_queue_FIFO_surrender(
+Thread_Control *_Thread_queue_FIFO_surrender(
Thread_queue_Queue *queue,
Thread_queue_Heads *heads,
Thread_Control *previous_owner,
@@ -243,6 +242,8 @@ static Thread_Control *_Thread_queue_FIFO_surrender(
{
Thread_Control *first;
+ (void) previous_owner;
+
first = _Thread_queue_FIFO_first( heads );
_Thread_queue_Queue_extract(
queue,
@@ -589,7 +590,7 @@ static void _Thread_queue_Priority_extract(
}
static Thread_Control *_Thread_queue_Priority_first(
- Thread_queue_Heads *heads
+ const Thread_queue_Heads *heads
)
{
Thread_queue_Priority_queue *priority_queue;
diff --git a/testsuites/libtests/malloctest/init.c b/testsuites/libtests/malloctest/init.c
index 1d91385683..1e5c14fe4b 100644
--- a/testsuites/libtests/malloctest/init.c
+++ b/testsuites/libtests/malloctest/init.c
@@ -122,9 +122,13 @@ static void test_heap_default_init(void)
static void test_free( void *addr )
{
+ uint32_t failed_allocs;
+
rtems_test_assert( _Heap_Free( &TestHeap, addr ) );
+ failed_allocs = TestHeap.stats.failed_allocs;
_Heap_Protection_free_all_delayed_blocks( &TestHeap );
+ rtems_test_assert( failed_allocs == TestHeap.stats.failed_allocs );
}
static void test_heap_cases_1(void)
diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c
index 4cad67a6ae..2deff3a482 100644
--- a/testsuites/libtests/tar01/init.c
+++ b/testsuites/libtests/tar01/init.c
@@ -7,6 +7,33 @@
* http://www.rtems.org/license/LICENSE.
*/
+/*
+ * Note on the used tar file: Generate the file on a system that supports
+ * symlinks with the following commands (tested on Linux - you might have to
+ * adapt on other systems):
+ *
+ * export WORK=some_work_directory
+ * rm -r ${WORK}
+ * mkdir -p ${WORK}/home/abc/def
+ * mkdir -p ${WORK}/home/dir
+ * cd ${WORK}
+ * echo "#! joel" > home/abc/def/test_script
+ * echo "ls -las /dev" >> home/abc/def/test_script
+ * chmod 755 home/abc/def/test_script
+ * echo "This is a test of loading an RTEMS filesystem from an" > home/test_file
+ * echo "initial tar image." >> home/test_file
+ * echo "Hello world" >> home/dir/file
+ * ln -s home/test_file symlink
+ * tar cf tar01.tar --format=ustar \
+ * symlink \
+ * home/test_file \
+ * home/abc/def/test_script \
+ * home/dir
+ *
+ * Note that "home/dir" is in the archive as separate directory. "home/abc" is
+ * only in the archive as a parent of the file "test_script".
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -95,6 +122,84 @@ void test_untar_from_memory(void)
}
+static void assert_file_content(
+ const char *name,
+ const char *expected_content,
+ ssize_t expected_size
+)
+{
+ char buf[16];
+ int fd;
+ int rd;
+
+ fd = open(name, O_RDONLY);
+ rtems_test_assert( fd >= 0 );
+ do {
+ rd = read(fd, buf, sizeof(buf));
+ rtems_test_assert( rd >= 0 );
+ if (rd > 0) {
+ rtems_test_assert( expected_size - rd >= 0 );
+ rtems_test_assert( memcmp(buf, expected_content, rd) == 0 );
+ expected_content += rd;
+ expected_size -= rd;
+ }
+ } while(rd > 0);
+ rtems_test_assert( expected_size == 0 );
+ close(fd);
+}
+
+static void assert_content_like_expected(void)
+{
+ const char *directories[] = {
+ "home",
+ "home/abc",
+ "home/abc/def",
+ "home/dir",
+ };
+ const char *symlinks[] = {
+ "symlink",
+ };
+ const struct {
+ const char *name;
+ const char *content;
+ } files[] = {
+ {
+ .name = "home/abc/def/test_script",
+ .content = "#! joel\nls -las /dev\n",
+ }, {
+ .name = "home/test_file",
+ .content = "This is a test of loading an RTEMS filesystem from an\n"
+ "initial tar image.\n",
+ }, {
+ .name = "home/dir/file",
+ .content = "Hello world\n",
+ }
+ };
+ size_t i;
+ struct stat st;
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(directories); ++i) {
+ lstat(directories[i], &st);
+ rtems_test_assert( S_ISDIR(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(symlinks); ++i) {
+ lstat(symlinks[i], &st);
+ rtems_test_assert( S_ISLNK(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(files); ++i) {
+ lstat(files[i].name, &st);
+ rtems_test_assert( S_ISREG(st.st_mode) );
+
+ assert_file_content(
+ files[i].name,
+ files[i].content,
+ strlen(files[i].content)
+ );
+ }
+}
+
void test_untar_from_file(void)
{
int fd;
@@ -119,13 +224,105 @@ void test_untar_from_file(void)
rv = chdir( "/dest" );
rtems_test_assert( rv == 0 );
- /* Untar it */
+ /* Case 1: Untar it into empty directory */
rv = Untar_FromFile( "/test.tar" );
printf("Untaring from file - ");
if (rv != UNTAR_SUCCESSFUL) {
printf ("error: untar failed: %i\n", rv);
exit(1);
}
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 2: Most files exist */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file into existing structure with one missing file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 3: An empty directory exists where a file should be */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite empty directory with file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 4: A file exists where a parent directory should be created */
+ rv = unlink("/dest/home/abc/def/test_script");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc/def");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/abc", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; file exists where parent dir should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 5: A non-empty directory exists where a file should be created */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/test_file/file",
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; non-empty dir where file should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/test_file/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 6: A file exists where a directory is explicitly in the archive */
+ rv = unlink("/dest/home/dir/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/dir");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/dir", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite file with explicit directory - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
printf ("successful\n");
/******************/
diff --git a/testsuites/libtests/tar01/tar01.doc b/testsuites/libtests/tar01/tar01.doc
index 060f98a813..adffdca291 100644
--- a/testsuites/libtests/tar01/tar01.doc
+++ b/testsuites/libtests/tar01/tar01.doc
@@ -20,3 +20,4 @@ directives:
concepts:
+ exercise these routines
++ check whether existing files are overwritten or not overwritten like expected
diff --git a/testsuites/libtests/tar01/tar01.scn b/testsuites/libtests/tar01/tar01.scn
index 68fa951881..dd72f9517b 100644
--- a/testsuites/libtests/tar01/tar01.scn
+++ b/testsuites/libtests/tar01/tar01.scn
@@ -1,9 +1,24 @@
-*** TAR01 TEST ***
-Untaring from memory - successful
+*** BEGIN OF TEST TAR 1 ***
+*** TEST VERSION: 6.0.0.e1efb4eb8a9d6dd5f6f37dafc9feb0a9e6a888f1
+*** TEST STATE: EXPECTED_PASS
+*** TEST BUILD: RTEMS_POSIX_API
+*** TEST TOOLS: 10.3.1 20210409 (RTEMS 6, RSB ad54d1dd3cf8249d9d39deb1dd28b2f294df062d-modified, Newlib eb03ac1)
+Untaring from memory - untar: memory at 0x11ece8 (10240)
+untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
+successful
========= /home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /home/abc/def/test_script: mode: 0755 want: 0755
========= /symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
@@ -11,35 +26,58 @@ initial tar image.
Copy tar image to test.tar
Untaring from file - successful
+Untar from file into existing structure with one missing file - successful
+Untar from file; overwrite empty directory with file - successful
+Untar from file; file exists where parent dir should be created - expected fail
+Untar from file; non-empty dir where file should be created - expected fail
+Untar from file; overwrite file with explicit directory - successful
========= /dest/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from memory - untar: dir: home
-untar: file: home/test_file (73)
+Untaring chunks from memory - untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
successful
========= /dest2/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest2/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest2/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest2/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from tgz- untar: dir: home
-untar: file: home/test_file (73)
-successful
+Untaring chunks from tgz - successful
========= /dest3/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest3/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest3/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest3/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-*** END OF TAR01 TEST ***
+
+
+*** END OF TEST TAR 1 ***
diff --git a/testsuites/libtests/tar01/tar01.tar b/testsuites/libtests/tar01/tar01.tar
index 6c6952ef18..9874f426d1 100644
--- a/testsuites/libtests/tar01/tar01.tar
+++ b/testsuites/libtests/tar01/tar01.tar
Binary files differ
diff --git a/testsuites/psxtests/psxdevctl01/test.c b/testsuites/psxtests/psxdevctl01/test.c
index b45725cb58..2fe7df1834 100644
--- a/testsuites/psxtests/psxdevctl01/test.c
+++ b/testsuites/psxtests/psxdevctl01/test.c
@@ -53,37 +53,16 @@ int main(
int dev_data;
void *dev_data_ptr;
size_t nbyte;
- int dev_info;
TEST_BEGIN();
- puts( "posix_devctl() FIONBIO on stdin return dev_info -- EBADF" );
- fd = 0;
- dcmd = FIONBIO;
- dev_data_ptr = &dev_data;
- nbyte = sizeof(dev_data);
- status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, &dev_info );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
- rtems_test_assert( dev_info == 0 );
-
- puts( "posix_devctl() FIONBIO on stdin NULL dev_info -- EBADF" );
- fd = 0;
- dcmd = FIONBIO;
- dev_data_ptr = NULL;
- nbyte = 0;
- status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
-
puts( "posix_devctl() SOCKCLOSE on invalid file descriptor -- EBADF" );
- fd = 21;
+ fd = -1;
dcmd = SOCKCLOSE;
dev_data_ptr = NULL;
nbyte = 0;
status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
- rtems_test_assert( status == -1 );
- rtems_test_assert( errno == EBADF );
+ rtems_test_assert( status == EBADF );
/*
* Create a file, open it, and close it via posix_devctl().
@@ -102,6 +81,50 @@ int main(
status = close( fd );
rtems_test_assert( status == -1 );
rtems_test_assert( errno == EBADF );
+
+ puts( "posix_devctl() FIONBIO with invalid nbyte -- EINVAL" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data_ptr = NULL;
+ nbyte = 0;
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EINVAL );
+
+ puts( "posix_devctl() FIONBIO with invalid file descriptor -- EBADF" );
+ fd = -1;
+ dcmd = FIONBIO;
+ dev_data_ptr = NULL;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EBADF );
+
+ puts( "posix_devctl() FIONBIO flag not zero -- 0" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data = 1;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == 0 );
+
+ puts( "posix_devctl() FIONBIO flag is zero -- 0" );
+ fd = 0;
+ dcmd = FIONBIO;
+ dev_data = 0;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == 0 );
+
+ puts( "posix_devctl() dcmd not valid value -- EBADF" );
+ fd = 0;
+ dcmd = 1;
+ dev_data = 0;
+ dev_data_ptr = &dev_data;
+ nbyte = sizeof(int);
+ status = posix_devctl( fd, dcmd, dev_data_ptr, nbyte, NULL );
+ rtems_test_assert( status == EBADF );
+
TEST_END();
exit(0);
}
diff --git a/testsuites/psxtests/psximfs02/init.c b/testsuites/psxtests/psximfs02/init.c
index 15b9137121..04f806f565 100644
--- a/testsuites/psxtests/psximfs02/init.c
+++ b/testsuites/psxtests/psximfs02/init.c
@@ -23,6 +23,8 @@
#include <rtems/malloc.h>
#include <rtems/libcsupport.h>
+#define MEMFILE_BYTES_PER_BLOCK 16
+
const char rtems_test_name[] = "PSXIMFS 2";
/* forward declarations to avoid warnings */
@@ -43,12 +45,17 @@ rtems_task Init(
static const uintptr_t slink_2_name_size [] = {
sizeof( slink_2_name )
};
+ static const uintptr_t some_blocks [] = {
+ MEMFILE_BYTES_PER_BLOCK * 10
+ };
+ static const char some_data[MEMFILE_BYTES_PER_BLOCK * 11];
int status = 0;
void *opaque;
char linkname_n[32] = {0};
char linkname_p[32] = {0};
int i;
+ int fd;
struct stat stat_buf;
TEST_BEGIN();
@@ -102,6 +109,27 @@ rtems_task Init(
rtems_test_assert( status == -1 );
rtems_test_assert( errno == EACCES );
+ puts( "Allocate most of heap with a little bit left" );
+ opaque = rtems_heap_greedy_allocate( some_blocks, 1 );
+
+ puts( "Create an empty file.");
+ status = mknod( "/foo", S_IFREG | S_IRWXU, 0LL );
+ rtems_test_assert( status == 0 );
+
+ puts( "Then increase it's size to more than remaining space" );
+ fd = open( "/foo", O_WRONLY | O_TRUNC);
+ rtems_test_assert( fd >= 0 );
+ status = write(fd, some_data, sizeof(some_data));
+ rtems_test_assert( status == -1);
+ rtems_test_assert( errno == ENOSPC );
+
+ puts( "Clean up again" );
+ status = close(fd);
+ rtems_test_assert( status == 0);
+ status = remove( "/foo" );
+ rtems_test_assert( status == 0);
+ rtems_heap_greedy_free( opaque );
+
puts( "Allocate most of heap" );
opaque = rtems_heap_greedy_allocate( mount_table_entry_size, 1 );
@@ -202,7 +230,7 @@ rtems_task Init(
#define CONFIGURE_FILESYSTEM_IMFS
#define CONFIGURE_MAXIMUM_TASKS 1
-#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK 16
+#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK MEMFILE_BYTES_PER_BLOCK
#define CONFIGURE_IMFS_ENABLE_MKFIFO
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index 62bb1aa685..1ea2501bd7 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -1783,6 +1783,24 @@ spstkalloc02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc02) \
$(support_includes)
endif
+if TEST_spstkalloc03
+sp_tests += spstkalloc03
+sp_screens += spstkalloc03/spstkalloc03.scn
+sp_docs += spstkalloc03/spstkalloc03.doc
+spstkalloc03_SOURCES = spstkalloc03/init.c
+spstkalloc03_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc03) \
+ $(support_includes)
+endif
+
+if TEST_spstkalloc04
+sp_tests += spstkalloc04
+sp_screens += spstkalloc04/spstkalloc04.scn
+sp_docs += spstkalloc04/spstkalloc04.doc
+spstkalloc04_SOURCES = spstkalloc04/init.c
+spstkalloc04_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc04) \
+ $(support_includes)
+endif
+
if TEST_spsysinit01
sp_tests += spsysinit01
sp_screens += spsysinit01/spsysinit01.scn
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index 9476e3b0d7..24ff0383e6 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -228,6 +228,8 @@ RTEMS_TEST_CHECK([spsize])
RTEMS_TEST_CHECK([spstdthreads01])
RTEMS_TEST_CHECK([spstkalloc])
RTEMS_TEST_CHECK([spstkalloc02])
+RTEMS_TEST_CHECK([spstkalloc03])
+RTEMS_TEST_CHECK([spstkalloc04])
RTEMS_TEST_CHECK([spsysinit01])
RTEMS_TEST_CHECK([spsyslock01])
RTEMS_TEST_CHECK([sptask_err01])
diff --git a/testsuites/sptests/spmrsp01/init.c b/testsuites/sptests/spmrsp01/init.c
index a5f645d534..801b679ec9 100644
--- a/testsuites/sptests/spmrsp01/init.c
+++ b/testsuites/sptests/spmrsp01/init.c
@@ -72,12 +72,6 @@ static void test_mrsp_create_errors(void)
create_not_defined(
RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
- | RTEMS_BINARY_SEMAPHORE
- | RTEMS_PRIORITY
- );
-
- create_not_defined(
- RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
| RTEMS_INHERIT_PRIORITY
| RTEMS_BINARY_SEMAPHORE
);
diff --git a/testsuites/sptests/spstkalloc03/init.c b/testsuites/sptests/spstkalloc03/init.c
new file mode 100644
index 0000000000..348afe7328
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/init.c
@@ -0,0 +1,103 @@
+/*
+ * COPYRIGHT (c) 2021.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <tmacros.h>
+
+#include <rtems/score/percpu.h>
+
+const char rtems_test_name[] = "SPSTKALLOC 3";
+
+static int thread_stacks_count = 0xff;
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+ rtems_test_assert(thread_stacks_count == 2);
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+static uint8_t stack_memory[RTEMS_MINIMUM_STACK_SIZE * 4];
+
+static int stack_offset_next;
+
+static void *allocate_helper(size_t size)
+{
+ size_t next;
+ void *alloc;
+
+ next = stack_offset_next + size;
+ rtems_test_assert( next < sizeof(stack_memory) );
+
+ alloc = &stack_memory[stack_offset_next];
+ stack_offset_next = next;
+ return alloc;
+}
+
+static void thread_stacks_initialize(size_t stack_space_size)
+{
+ rtems_test_assert(thread_stacks_count == 0xff);
+ thread_stacks_count = 0;
+}
+
+static void *thread_stacks_allocate(size_t stack_size)
+{
+ rtems_test_assert(thread_stacks_count == 1);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+static void thread_stacks_free(void *addr)
+{
+ rtems_test_assert(false);
+}
+
+static void *thread_stacks_allocate_for_idle(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ rtems_test_assert(thread_stacks_count == 0);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+/*
+ * Configure the thread stack allocators to not use the workspace. This should
+ * eliminate all uses of the Workspace for most BSPs.
+ */
+#define CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
+#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT thread_stacks_initialize
+#define CONFIGURE_TASK_STACK_ALLOCATOR thread_stacks_allocate
+#define CONFIGURE_TASK_STACK_DEALLOCATOR thread_stacks_free
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE thread_stacks_allocate_for_idle
+
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.doc b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
new file mode 100644
index 0000000000..797716b623
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
@@ -0,0 +1,19 @@
+# COPYRIGHT (c) 2021.
+# On-Line Applications Research Corporation (OAR).
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: spstkalloc03
+
+directives:
+
+concepts:
+
++ Ensure that the task stack allocator including IDLE thread
+ stack allocator works.
+
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.scn b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
new file mode 100644
index 0000000000..45c67ef1fb
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTKALLOC 3 ***
+*** END OF TEST SPSTKALLOC 3 ***
diff --git a/testsuites/sptests/spstkalloc04/init.c b/testsuites/sptests/spstkalloc04/init.c
new file mode 100644
index 0000000000..16f4ec65ca
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/init.c
@@ -0,0 +1,82 @@
+/*
+ * COPYRIGHT (c) 2021.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <tmacros.h>
+
+#include <rtems/score/percpu.h>
+
+const char rtems_test_name[] = "SPSTKALLOC 4";
+
+static int thread_stacks_count = 0;
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+ rtems_test_assert(thread_stacks_count == 1);
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+static uint8_t stack_memory[RTEMS_MINIMUM_STACK_SIZE * 4];
+
+static int stack_offset_next;
+
+static void *allocate_helper(size_t size)
+{
+ size_t next;
+ void *alloc;
+
+ next = stack_offset_next + size;
+ rtems_test_assert( next < sizeof(stack_memory) );
+
+ alloc = &stack_memory[stack_offset_next];
+ stack_offset_next = next;
+ return alloc;
+}
+
+static void *thread_stacks_allocate_for_idle(
+ uint32_t cpu,
+ size_t stack_size
+)
+{
+ rtems_test_assert(thread_stacks_count == 0);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+/*
+ * Configure the IDLE thread stack allocators. This is a special
+ * case where there is an IDLE thread stack allocator but no custom
+ * allocator set for other threads.
+ */
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE thread_stacks_allocate_for_idle
+
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spstkalloc04/spstkalloc04.doc b/testsuites/sptests/spstkalloc04/spstkalloc04.doc
new file mode 100644
index 0000000000..a1ed5b22cb
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/spstkalloc04.doc
@@ -0,0 +1,20 @@
+# COPYRIGHT (c) 2021.
+# On-Line Applications Research Corporation (OAR).
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: spstkalloc04
+
+directives:
+
+concepts:
+
++ Ensure that the task stack allocator including IDLE thread
+ stack allocator works when a custom allocator is NOT provided
+ for other threads.
+
diff --git a/testsuites/sptests/spstkalloc04/spstkalloc04.scn b/testsuites/sptests/spstkalloc04/spstkalloc04.scn
new file mode 100644
index 0000000000..f0919ec2d4
--- /dev/null
+++ b/testsuites/sptests/spstkalloc04/spstkalloc04.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTKALLOC 4 ***
+*** END OF TEST SPSTKALLOC 4 ***
diff --git a/testsuites/sptests/sptask_err04/task1.c b/testsuites/sptests/sptask_err04/task1.c
index 29b63db5f4..c1f59d81fb 100644
--- a/testsuites/sptests/sptask_err04/task1.c
+++ b/testsuites/sptests/sptask_err04/task1.c
@@ -165,6 +165,15 @@ rtems_task Task_1(
);
puts( "TA1 - rtems_task_start - RTEMS_INVALID_ID" );
+ /* NULL entry point */
+ status = rtems_task_start( RTEMS_SELF, NULL, 0 );
+ fatal_directive_status(
+ status,
+ RTEMS_INVALID_ADDRESS,
+ "rtems_task_start with NULL entry point"
+ );
+ puts( "TA1 - rtems_task_start - RTEMS_INVALID_ADDRESS" );
+
/* already started */
status = rtems_task_start( RTEMS_SELF, Task_1, 0 );
fatal_directive_status(
diff --git a/testsuites/sptests/sptimecounter01/init.c b/testsuites/sptests/sptimecounter01/init.c
index 81b705473e..12d5a7820d 100644
--- a/testsuites/sptests/sptimecounter01/init.c
+++ b/testsuites/sptests/sptimecounter01/init.c
@@ -196,11 +196,11 @@ void boot_card(const char *cmdline)
assert(bt.sec == 1);
assert(bt.frac == 18446744073708);
- /* Ensure that the fraction overflows and the second remains constant */
+ /* Check that a large delta yields a correct time */
ctx->counter = (0xf0000000 | 1) + TEST_FREQ;
rtems_bsd_binuptime(&bt);
assert(ctx->counter == (0xf0000000 | 2) + TEST_FREQ);
- assert(bt.sec == 1);
+ assert(bt.sec == 2);
assert(bt.frac == 18446742522092);
test_install(ctx);