Exemple #1
0
static void test_interrupt_locks( void )
{
  rtems_mode normal_interrupt_level = get_interrupt_level();
  rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER;
  rtems_interrupt_lock lock;
  rtems_interrupt_lock_context lock_context;

  rtems_interrupt_lock_initialize( &lock );
  rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 );

  rtems_interrupt_lock_acquire( &lock, &lock_context );
  rtems_test_assert( normal_interrupt_level != get_interrupt_level() );
  rtems_interrupt_lock_release( &lock, &lock_context );

  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );

  rtems_interrupt_lock_acquire_isr( &lock, &lock_context );
  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
  rtems_interrupt_lock_release_isr( &lock, &lock_context );

  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );

  rtems_interrupt_lock_destroy( &lock );
  rtems_interrupt_lock_destroy( &initialized );
}
Exemple #2
0
static void test_by_function_level(int fl, bool dirty)
{
  rtems_interrupt_lock lock;
  rtems_interrupt_lock_context lock_context;
  int s;
  uint64_t min;
  uint64_t q1;
  uint64_t q2;
  uint64_t q3;
  uint64_t max;

  rtems_interrupt_lock_initialize(&lock, "test");
  rtems_interrupt_lock_acquire(&lock, &lock_context);

  for (s = 0; s < SAMPLES; ++s) {
    call_at_level(fl, fl, s, dirty);
  }

  rtems_interrupt_lock_release(&lock, &lock_context);
  rtems_interrupt_lock_destroy(&lock);

  sort_t();

  min = t[0];
  q1 = t[(1 * SAMPLES) / 4];
  q2 = t[SAMPLES / 2];
  q3 = t[(3 * SAMPLES) / 4];
  max = t[SAMPLES - 1];

  printf(
    "    <Sample functionNestLevel=\"%i\">\n"
    "      <Min unit=\"ns\">%" PRIu64 "</Min>"
      "<Q1 unit=\"ns\">%" PRIu64 "</Q1>"
      "<Q2 unit=\"ns\">%" PRIu64 "</Q2>"
      "<Q3 unit=\"ns\">%" PRIu64 "</Q3>"
      "<Max unit=\"ns\">%" PRIu64 "</Max>\n"
    "    </Sample>\n",
    fl,
    rtems_counter_ticks_to_nanoseconds(min),
    rtems_counter_ticks_to_nanoseconds(q1),
    rtems_counter_ticks_to_nanoseconds(q2),
    rtems_counter_ticks_to_nanoseconds(q3),
    rtems_counter_ticks_to_nanoseconds(max)
  );
}
Exemple #3
0
static rtems_termios_tty *
rtems_termios_open_tty(
  rtems_device_major_number      major,
  rtems_device_minor_number      minor,
  rtems_libio_open_close_args_t *args,
  rtems_termios_tty             *tty,
  rtems_termios_device_node     *device_node,
  const rtems_termios_callbacks *callbacks
)
{
  rtems_status_code sc;

  if (tty == NULL) {
    static char c = 'a';

    /*
     * Create a new device
     */
    tty = calloc (1, sizeof (struct rtems_termios_tty));
    if (tty == NULL) {
      return NULL;
    }
    /*
     * allocate raw input buffer
     */
    tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
    tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
    if (tty->rawInBuf.theBuf == NULL) {
            free(tty);
      return NULL;
    }
    /*
     * allocate raw output buffer
     */
    tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
    tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
    if (tty->rawOutBuf.theBuf == NULL) {
            free((void *)(tty->rawInBuf.theBuf));
            free(tty);
      return NULL;
    }
    /*
     * allocate cooked buffer
     */
    tty->cbuf  = malloc (CBUFSIZE);
    if (tty->cbuf == NULL) {
            free((void *)(tty->rawOutBuf.theBuf));
            free((void *)(tty->rawInBuf.theBuf));
            free(tty);
      return NULL;
    }
    /*
     * Initialize wakeup callbacks
     */
    tty->tty_snd.sw_pfn = NULL;
    tty->tty_snd.sw_arg = NULL;
    tty->tty_rcv.sw_pfn = NULL;
    tty->tty_rcv.sw_arg = NULL;
    tty->tty_rcvwakeup  = 0;

    tty->minor = minor;
    tty->major = major;

    /*
     * Set up mutex semaphores
     */
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'i', c),
      1,
      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
      RTEMS_NO_PRIORITY,
      &tty->isem);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'o', c),
      1,
      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
      RTEMS_NO_PRIORITY,
      &tty->osem);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'x', c),
      0,
      RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
      RTEMS_NO_PRIORITY,
      &tty->rawOutBuf.Semaphore);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    tty->rawOutBufState = rob_idle;

    /*
     * Set callbacks
     */
    if (device_node != NULL) {
      device_node->tty = tty;
      tty->handler = *device_node->handler;
      tty->device_node = device_node;
      tty->device_context = device_node->context;
      memset(&tty->device, 0, sizeof(tty->device));
    } else {
      tty->handler.first_open = callbacks->firstOpen != NULL ?
        rtems_termios_callback_firstOpen : NULL;
      tty->handler.last_close = callbacks->lastClose != NULL ?
        rtems_termios_callback_lastClose : NULL;
      tty->handler.poll_read = callbacks->pollRead != NULL ?
        rtems_termios_callback_pollRead : NULL;
      tty->handler.write = callbacks->write != NULL ?
        rtems_termios_callback_write : NULL;
      tty->handler.set_attributes = callbacks->setAttributes != NULL ?
        rtems_termios_callback_setAttributes : NULL;
      tty->handler.stop_remote_tx = callbacks->stopRemoteTx != NULL ?
        rtems_termios_callback_stopRemoteTx : NULL;
      tty->handler.start_remote_tx = callbacks->startRemoteTx != NULL ?
        rtems_termios_callback_startRemoteTx : NULL;
      tty->handler.mode = callbacks->outputUsesInterrupts;
      tty->device_context = NULL;
      tty->device_node = NULL;
      tty->device = *callbacks;
    }

    rtems_interrupt_lock_initialize (&tty->interrupt_lock, "Termios");

    /*
     * Create I/O tasks
     */
    if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
      sc = rtems_task_create (
                                   rtems_build_name ('T', 'x', 'T', c),
           TERMIOS_TXTASK_PRIO,
           TERMIOS_TXTASK_STACKSIZE,
           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
           RTEMS_NO_ASR,
           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
           &tty->txTaskId);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
      sc = rtems_task_create (
                                   rtems_build_name ('R', 'x', 'T', c),
           TERMIOS_RXTASK_PRIO,
           TERMIOS_RXTASK_STACKSIZE,
           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
           RTEMS_NO_ASR,
           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
           &tty->rxTaskId);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);

    }
    if ((tty->handler.poll_read == NULL) ||
        (tty->handler.mode == TERMIOS_TASK_DRIVEN)){
      sc = rtems_semaphore_create (
        rtems_build_name ('T', 'R', 'r', c),
        0,
        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY,
        RTEMS_NO_PRIORITY,
        &tty->rawInBuf.Semaphore);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
    }

    /*
     * Set default parameters
     */
    tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
    tty->termios.c_oflag = OPOST | ONLCR | XTABS;
    tty->termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
    tty->termios.c_lflag =
       ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;

    tty->termios.c_cc[VINTR] = '\003';
    tty->termios.c_cc[VQUIT] = '\034';
    tty->termios.c_cc[VERASE] = '\177';
    tty->termios.c_cc[VKILL] = '\025';
    tty->termios.c_cc[VEOF] = '\004';
    tty->termios.c_cc[VEOL] = '\000';
    tty->termios.c_cc[VEOL2] = '\000';
    tty->termios.c_cc[VSTART] = '\021';
    tty->termios.c_cc[VSTOP] = '\023';
    tty->termios.c_cc[VSUSP] = '\032';
    tty->termios.c_cc[VREPRINT] = '\022';
    tty->termios.c_cc[VDISCARD] = '\017';
    tty->termios.c_cc[VWERASE] = '\027';
    tty->termios.c_cc[VLNEXT] = '\026';

    /* start with no flow control, clear flow control flags */
    tty->flow_ctrl = 0;
    /*
     * set low/highwater mark for XON/XOFF support
     */
    tty->lowwater  = tty->rawInBuf.Size * 1/2;
    tty->highwater = tty->rawInBuf.Size * 3/4;
    /*
     * Bump name characer
     */
    if (c++ == 'z')
      c = 'a';

  }
  args->iop->data1 = tty;
  if (!tty->refcount++) {
    if (tty->handler.first_open &&
        !(*tty->handler.first_open)(tty, args)) {
      rtems_termios_destroy_tty(tty, args, false);
      return NULL;
    }

    /*
     * start I/O tasks, if needed
     */
    if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
      sc = rtems_task_start(
        tty->rxTaskId, rtems_termios_rxdaemon, (rtems_task_argument)tty);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);

      sc = rtems_task_start(
        tty->txTaskId, rtems_termios_txdaemon, (rtems_task_argument)tty);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
    }
  }

  return tty;
}
Exemple #4
0
/*
 * Open a termios device
 */
rtems_status_code
rtems_termios_open (
  rtems_device_major_number      major,
  rtems_device_minor_number      minor,
  void                          *arg,
  const rtems_termios_callbacks *callbacks
)
{
  rtems_status_code sc;
  rtems_libio_open_close_args_t *args = arg;
  struct rtems_termios_tty *tty;

  /*
   * See if the device has already been opened
   */
  sc = rtems_semaphore_obtain(
    rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
  if (sc != RTEMS_SUCCESSFUL)
    return sc;

  for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
    if ((tty->major == major) && (tty->minor == minor))
      break;
  }

  if (tty == NULL) {
    static char c = 'a';

    /*
     * Create a new device
     */
    tty = calloc (1, sizeof (struct rtems_termios_tty));
    if (tty == NULL) {
      rtems_semaphore_release (rtems_termios_ttyMutex);
      return RTEMS_NO_MEMORY;
    }
    /*
     * allocate raw input buffer
     */
    tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
    tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
    if (tty->rawInBuf.theBuf == NULL) {
            free(tty);
      rtems_semaphore_release (rtems_termios_ttyMutex);
      return RTEMS_NO_MEMORY;
    }
    /*
     * allocate raw output buffer
     */
    tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
    tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
    if (tty->rawOutBuf.theBuf == NULL) {
            free((void *)(tty->rawInBuf.theBuf));
            free(tty);
      rtems_semaphore_release (rtems_termios_ttyMutex);
      return RTEMS_NO_MEMORY;
    }
    /*
     * allocate cooked buffer
     */
    tty->cbuf  = malloc (CBUFSIZE);
    if (tty->cbuf == NULL) {
            free((void *)(tty->rawOutBuf.theBuf));
            free((void *)(tty->rawInBuf.theBuf));
            free(tty);
      rtems_semaphore_release (rtems_termios_ttyMutex);
      return RTEMS_NO_MEMORY;
    }
    /*
     * Initialize wakeup callbacks
     */
    tty->tty_snd.sw_pfn = NULL;
    tty->tty_snd.sw_arg = NULL;
    tty->tty_rcv.sw_pfn = NULL;
    tty->tty_rcv.sw_arg = NULL;
    tty->tty_rcvwakeup  = 0;

    /*
     * link tty
     */
    tty->forw = rtems_termios_ttyHead;
    tty->back = NULL;
    if (rtems_termios_ttyHead != NULL)
      rtems_termios_ttyHead->back = tty;
    rtems_termios_ttyHead = tty;
    if (rtems_termios_ttyTail == NULL)
      rtems_termios_ttyTail = tty;

    tty->minor = minor;
    tty->major = major;

    /*
     * Set up mutex semaphores
     */
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'i', c),
      1,
      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
      RTEMS_NO_PRIORITY,
      &tty->isem);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'o', c),
      1,
      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
      RTEMS_NO_PRIORITY,
      &tty->osem);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    sc = rtems_semaphore_create (
      rtems_build_name ('T', 'R', 'x', c),
      0,
      RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
      RTEMS_NO_PRIORITY,
      &tty->rawOutBuf.Semaphore);
    if (sc != RTEMS_SUCCESSFUL)
      rtems_fatal_error_occurred (sc);
    tty->rawOutBufState = rob_idle;

    /*
     * Set callbacks
     */
    tty->device = *callbacks;

    rtems_interrupt_lock_initialize (&tty->interrupt_lock, "Termios");

    /*
     * Create I/O tasks
     */
    if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
      sc = rtems_task_create (
                                   rtems_build_name ('T', 'x', 'T', c),
           TERMIOS_TXTASK_PRIO,
           TERMIOS_TXTASK_STACKSIZE,
           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
           RTEMS_NO_ASR,
           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
           &tty->txTaskId);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
      sc = rtems_task_create (
                                   rtems_build_name ('R', 'x', 'T', c),
           TERMIOS_RXTASK_PRIO,
           TERMIOS_RXTASK_STACKSIZE,
           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
           RTEMS_NO_ASR,
           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
           &tty->rxTaskId);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);

    }
    if ((tty->device.pollRead == NULL) ||
        (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
      sc = rtems_semaphore_create (
        rtems_build_name ('T', 'R', 'r', c),
        0,
        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY,
        RTEMS_NO_PRIORITY,
        &tty->rawInBuf.Semaphore);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
    }

    /*
     * Set default parameters
     */
    tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
    tty->termios.c_oflag = OPOST | ONLCR | XTABS;
    tty->termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
    tty->termios.c_lflag =
       ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;

    tty->termios.c_cc[VINTR] = '\003';
    tty->termios.c_cc[VQUIT] = '\034';
    tty->termios.c_cc[VERASE] = '\177';
    tty->termios.c_cc[VKILL] = '\025';
    tty->termios.c_cc[VEOF] = '\004';
    tty->termios.c_cc[VEOL] = '\000';
    tty->termios.c_cc[VEOL2] = '\000';
    tty->termios.c_cc[VSTART] = '\021';
    tty->termios.c_cc[VSTOP] = '\023';
    tty->termios.c_cc[VSUSP] = '\032';
    tty->termios.c_cc[VREPRINT] = '\022';
    tty->termios.c_cc[VDISCARD] = '\017';
    tty->termios.c_cc[VWERASE] = '\027';
    tty->termios.c_cc[VLNEXT] = '\026';

    /* start with no flow control, clear flow control flags */
    tty->flow_ctrl = 0;
    /*
     * set low/highwater mark for XON/XOFF support
     */
    tty->lowwater  = tty->rawInBuf.Size * 1/2;
    tty->highwater = tty->rawInBuf.Size * 3/4;
    /*
     * Bump name characer
     */
    if (c++ == 'z')
      c = 'a';

  }
  args->iop->data1 = tty;
  if (!tty->refcount++) {
    if (tty->device.firstOpen)
      (*tty->device.firstOpen)(major, minor, arg);

    /*
     * start I/O tasks, if needed
     */
    if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
      sc = rtems_task_start(
        tty->rxTaskId, rtems_termios_rxdaemon, (rtems_task_argument)tty);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);

      sc = rtems_task_start(
        tty->txTaskId, rtems_termios_txdaemon, (rtems_task_argument)tty);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
    }
  }
  rtems_semaphore_release (rtems_termios_ttyMutex);
  return RTEMS_SUCCESSFUL;
}
Exemple #5
0
static void test_data_flush_and_invalidate(void)
{
  if (rtems_cache_get_data_line_size() > 0) {
    rtems_interrupt_lock lock;
    rtems_interrupt_lock_context lock_context;
    volatile int *vdata = &data[0];
    int n = 32;
    int i;
    size_t data_size = n * sizeof(data[0]);
    bool write_through;

    printf("data cache flush and invalidate test\n");

    rtems_interrupt_lock_initialize(&lock, "test");
    rtems_interrupt_lock_acquire(&lock, &lock_context);

    for (i = 0; i < n; ++i) {
      vdata[i] = i;
    }

    rtems_cache_flush_multiple_data_lines(&data[0], data_size);

    for (i = 0; i < n; ++i) {
      rtems_test_assert(vdata[i] == i);
    }

    for (i = 0; i < n; ++i) {
      vdata[i] = ~i;
    }

    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);

    write_through = vdata[0] == ~0;
    if (write_through) {
      for (i = 0; i < n; ++i) {
        rtems_test_assert(vdata[i] == ~i);
      }
    } else {
      for (i = 0; i < n; ++i) {
        rtems_test_assert(vdata[i] == i);
      }
    }

    for (i = 0; i < n; ++i) {
      vdata[i] = ~i;
    }

    rtems_cache_flush_multiple_data_lines(&data[0], data_size);
    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);

    for (i = 0; i < n; ++i) {
      rtems_test_assert(vdata[i] == ~i);
    }

    rtems_interrupt_lock_release(&lock, &lock_context);
    rtems_interrupt_lock_destroy(&lock);

    printf(
      "data cache operations by line passed the test (%s cache detected)\n",
      write_through ? "write-through" : "copy-back"
    );
  } else {
    printf(
      "skip data cache flush and invalidate test"
        " due to cache line size of zero\n"
    );
  }

  /* Make sure these are nops */
  rtems_cache_flush_multiple_data_lines(NULL, 0);
  rtems_cache_invalidate_multiple_data_lines(NULL, 0);
}
Exemple #6
0
static void test_timing(void)
{
  rtems_interrupt_lock lock;
  rtems_interrupt_lock_context lock_context;
  size_t data_size = sizeof(data);
  uint64_t d[3];
  uint32_t cache_level;
  size_t cache_size;

  rtems_interrupt_lock_initialize(&lock, "test");

  printf(
    "data cache line size %zi bytes\n"
    "data cache size %zi bytes\n",
    rtems_cache_get_data_line_size(),
    rtems_cache_get_data_cache_size(0)
  );

  cache_level = 1;
  cache_size = rtems_cache_get_data_cache_size(cache_level);
  while (cache_size > 0) {
    printf(
      "data cache level %" PRIu32 " size %zi bytes\n",
      cache_level,
      cache_size
    );
    ++cache_level;
    cache_size = rtems_cache_get_data_cache_size(cache_level);
  }

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = load();
  d[1] = load();
  rtems_cache_flush_entire_data();
  d[2] = load();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "load %zi bytes with flush entire data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with flushed cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = load();
  d[1] = load();
  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
  d[2] = load();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "load %zi bytes with flush multiple data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with flushed cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = load();
  d[1] = load();
  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
  d[2] = load();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "load %zi bytes with invalidate multiple data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with invalidated cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = store();
  d[1] = store();
  rtems_cache_flush_entire_data();
  d[2] = store();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "store %zi bytes with flush entire data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with flushed cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = store();
  d[1] = store();
  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
  d[2] = store();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "store %zi bytes with flush multiple data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with flushed cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = store();
  d[1] = store();
  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
  d[2] = store();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "store %zi bytes with invalidate multiple data\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with invalidated cache %" PRIu64 " ns\n",
    data_size,
    d[0],
    d[1],
    d[2]
  );

  printf(
    "instruction cache line size %zi bytes\n"
    "instruction cache size %zi bytes\n",
    rtems_cache_get_instruction_line_size(),
    rtems_cache_get_instruction_cache_size(0)
  );

  cache_level = 1;
  cache_size = rtems_cache_get_instruction_cache_size(cache_level);
  while (cache_size > 0) {
    printf(
      "instruction cache level %" PRIu32 " size %zi bytes\n",
      cache_level,
      cache_size
    );
    ++cache_level;
    cache_size = rtems_cache_get_instruction_cache_size(cache_level);
  }

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = do_some_work();
  d[1] = do_some_work();
  rtems_cache_invalidate_entire_instruction();
  d[2] = do_some_work();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "invalidate entire instruction\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with invalidated cache %" PRIu64 " ns\n",
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_acquire(&lock, &lock_context);

  d[0] = do_some_work();
  d[1] = do_some_work();
  rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096);
  d[2] = do_some_work();

  rtems_interrupt_lock_release(&lock, &lock_context);

  printf(
    "invalidate multiple instruction\n"
    "  duration with normal cache %" PRIu64 " ns\n"
    "  duration with warm cache %" PRIu64 " ns\n"
    "  duration with invalidated cache %" PRIu64 " ns\n",
    d[0],
    d[1],
    d[2]
  );

  rtems_interrupt_lock_destroy(&lock);
}