| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #include <autoconf.h> |
| #include <sel4test-driver/gen_config.h> |
| #include <sel4/sel4.h> |
| #include <sel4/benchmark_track_types.h> |
| #include <sel4utils/benchmark_track.h> |
| #include <vka/object.h> |
| #include <vka/capops.h> |
| #include <platsupport/local_time_manager.h> |
| |
| #include "../timer.h" |
| |
| #include <utils/util.h> |
| |
| #if CONFIG_MAX_NUM_NODES > 1 && CONFIG_ARCH_ARM && CONFIG_TRACK_KERNEL_ENTRIES |
| |
| static int is_timer_interrupt(driver_env_t env, int irq) |
| { |
| int i; |
| |
| for (i = 0; i < env->timer.to.nirqs; i++) { |
| if (irq == env->timer.to.irqs[i].irq.irq.number) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| static int override_timer_irqs(driver_env_t env, int targetCore) |
| { |
| sel4ps_irq_t irq; |
| cspacepath_t path; |
| seL4_Error err; |
| int i; |
| |
| for (i = 0; i < env->timer.to.nirqs; i++) { |
| irq = env->timer.to.irqs[i]; |
| path = irq.handler_path; |
| /* Clear the current IRQ handler */ |
| err = vka_cnode_delete(&path); |
| test_assert(err == seL4_NoError); |
| |
| /* And replace it by the new, core specific handler */ |
| err = seL4_IRQControl_GetTriggerCore(seL4_CapIRQControl, irq.irq.irq.number, |
| 1, path.root, path.capPtr, path.capDepth, 1 << targetCore); |
| test_assert(err == seL4_NoError); |
| |
| /* Rebind it with its notification object */ |
| err = seL4_IRQHandler_SetNotification(irq.handler_path.capPtr, irq.badged_ntfn_path.capPtr); |
| test_assert(err == seL4_NoError); |
| } |
| } |
| |
| static int test_core(driver_env_t env, int core) |
| { |
| int i; |
| seL4_Error err; |
| |
| override_timer_irqs(env, core); |
| err = ltimer_set_timeout(&env->timer.ltimer, 1 * NS_IN_MS, TIMEOUT_PERIODIC); |
| test_assert_fatal(!err); |
| |
| for (i = 0; i < 10; i++) { |
| wait_for_timer_interrupt(env); |
| } |
| |
| err = ltimer_reset(&env->timer.ltimer); |
| test_assert_fatal(!err); |
| return 1; |
| } |
| |
| static int test_core_affinity_interrupt(driver_env_t env) |
| { |
| cspacepath_t path; |
| seL4_Error err; |
| seL4_CPtr logBufferCap; |
| benchmark_track_kernel_entry_t *logBuffer; |
| unsigned nbLogEntries, i; |
| unsigned irqPerNode[CONFIG_MAX_NUM_NODES] = {0}; |
| |
| /* Set up logs */ |
| logBuffer = vspace_new_pages(&env->vspace, seL4_AllRights, 1, seL4_SectionBits); |
| logBufferCap = vspace_get_cap(&env->vspace, logBuffer); |
| seL4_BenchmarkSetLogBuffer(logBufferCap); |
| |
| /* Start logging */ |
| seL4_BenchmarkResetLog(); |
| |
| for (i = 0; i < CONFIG_MAX_NUM_NODES; i++) { |
| test_core(env, i); /* Generate 10 interrupts routed to core i */ |
| } |
| |
| /* Stop logging */ |
| nbLogEntries = seL4_BenchmarkFinalizeLog(); |
| |
| /* Iterate through the log to count all timer irqs delivered to each core */ |
| for (i = 0; i < nbLogEntries; i++) { |
| if (logBuffer[i].entry.path == Entry_Interrupt) { |
| uint32_t irqVal = logBuffer[i].entry.word; |
| uint8_t irqCore = logBuffer[i].entry.core; |
| |
| if (is_timer_interrupt(env, irqVal)) { |
| irqPerNode[irqCore]++; |
| } |
| } |
| } |
| |
| /* Assert that exactly 10 timer irqs were delivered to each core */ |
| for (i = 0; i < CONFIG_MAX_NUM_NODES; i++) { |
| test_assert(irqPerNode[i] == 10); |
| } |
| return sel4test_get_result(); |
| } |
| DEFINE_TEST_BOOTSTRAP(SMPIRQ0001, "Test multicore irqs", test_core_affinity_interrupt, true); |
| |
| #endif |