进入多核时代后,ARM公司提供了timer的硬件设计,集成在了自己的多核结构中。例如:在Cortex A15 MPcore的硬件体系结构中有一个HW block叫做Generic Timer(该硬件取代了A9中的global timer、private timer的功能),为系统提供了计时以及触发timer event的功能。
ARM generic timer的硬件block主要是SOC上的System counter(多个process共享,用来记录时间的流逝)以及附着在各个processor上的Timer(用于触发timer event)组成,其他的generic timer的硬件电路主要是用来进行交流generic time event的。例如各个processor中的timer和system counter外设进行交互,各个processor中的timer进行信息交互。System counter的功能很简单,就是计算输入时钟已经过了多少个clock,开始的时候是0,每一个clock,System counter会加一。System counter的counter value需要分发到各个timer中,也就是说,从各个timer的角度看,system counter value应该是一致的。Timer其实就是定时器,它可以定义一段指定的时间,当时间到了,就会assert一个外部的输出信号(可以输出到GIC,作为一个interrupt source)。
除了基本的计时功能,system count还提供了event stream的功能。我们知道,ARMv7的处理器提供了wait for event的机制,该机制允许processor进入low power state并等待event的到来。这个event可能是来自另外的process的send event指令,也可能是外部HW block产生的event,比如来自system counter的wake-up event。
选自《Linux时间子系统之(十七):ARM generic timer驱动代码分析》
main()
{
HalClockFreqWrite(OS_SYS_CLOCK);
。。。
OsMain() {
。。。
ret = OsTickInit(g_sysClock, LOSCFG_BASE_CORE_TICK_PER_SECOND) {
HalClockInit(){
g_sysClock = HalClockFreqRead(); ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0); if (ret != LOS_OK) { PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret); }
}
}
。。。
}
。。。
OsStart() {
OsTickStart() {
HalClockStart() {
HalIrqUnmask(OS_TICK_INT_NUM);
/* triggle the first tick */ TimerCtlWrite(0); TimerTvalWrite(OS_CYCLE_PER_TICK); TimerCtlWrite(1);
}
}
。。。
}
while (1) { __asm volatile("wfi"); }
}
测试:
ARCH_ClockStart() {
/* set smp system counter freq */ WRITE_TIMER_REG32(TIMER_REG_CNTFRQ, OS_SYS_CLOCK);
WRITE_TIMER_REG32(TIMER_REG_CTL, 0); WRITE_TIMER_REG32(TIMER_REG_TVAL, 0); WRITE_TIMER_REG64(TIMER_REG_CVAL, 0); WRITE_TIMER_REG32(TIMER_REG_CTL, 1);
} ret = RTOS_HAL_HwiCreate(OS_TICK_INT_NUM, OS_TickHandler, OS_NULL) {
。。。
ARCH_IrqUnmask(no);
。。。
} if (ret != OS_ERR_NOERR) { EPRINTK_ERR("create HWI os tick irq failed, ret:0xX\n", ret); RTOS_Hang(); }
eprintk("CPU#%u: releasing %u secondary cores ...\n", cpuId, CORE_NUM - 1); //ARCH_ReleaseSecondaryCores(); /* wait until all APs are ready */ //while (RTOS_ATOMIC_Read(&cpus) < CORE_NUM) { // ARCH_WFE(); //}
//OS_Start();
while(1) { uss = ARCH_ClockGetUs();
s = uss / 1000000; m = s / 60; h = m / 60; m = m % 60; s = s % 60;
uss = uss % 1000000;
ms = uss / 1000; us = uss % 1000; eprintk("\rCPU#%u: %u:u:u.u.u WFI", cpuId, h, m, s, ms, us); ARCH_WFI(); }
呈现时钟效果
CPU#0: 0:08:35.210.000 WFI
但是呢,中断没有,一直在找原因,为什么呢没有中断产生,
然后各种找,各种想,某一刻看到
/* arch/hw.S */ os_base_t ARCH_HW_InterruptDisable(void); void ARCH_HW_InterruptEnable(os_base_t level);
ARCH_HW_InterruptDisable()在一开始执行了,那就要调用ARCH_HW_InterruptEnable()?
一试,还真可以了。
修改,
static void OS_TickHandler(void *param) { u32 cpuId = ARCH_CurCpuId(); u32 intSave;
ARCH_ClockStop();
//TICK_LOCK(intSave); ++gTickCount[cpuId]; eprintk("CPU#%u: tick %u\n", cpuId, gTickCount[cpuId]); //TICK_UNLOCK(intSave);
//OsTimesliceCheck(); //OsTaskScan(); /* task timeout scan */ //OsSwtmrScan();
ARCH_ClockContinue(); }
void RTOS_Main(os_base_t osMemStart) { s32 ret = 0; //u32 cpuId = ARCH_CurCpuId();
ARCH_HW_InterruptDisable();
RTOS_HAL_Init();
eprintk("\nRTOS SMP %s*%d [v%d.%d.%d %s %s]\n", ARCH_GetCpuInfo(), CORE_NUM, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, __DATE__, __TIME__);
RTOS_MEM_Init(osMemStart, KERNEL_VADDR_SIZE - (osMemStart - KERNEL_VADDR_BASE));
ARCH_ClockInit(); ret = RTOS_HAL_HwiCreate(OS_TICK_INT_NUM, OS_TickHandler, OS_NULL); if (ret != OS_ERR_NOERR) { EPRINTK_ERR("create HWI os tick irq failed, ret:0xX\n", ret); RTOS_Hang(); }
ARCH_ClockStart(OS_TICK_INT_NUM);
//eprintk("CPU#%u: releasing %u secondary cores ...\n", cpuId, CORE_NUM - 1); //ARCH_ReleaseSecondaryCores(); /* wait until all APs are ready */ //while (RTOS_ATOMIC_Read(&cpus) < CORE_NUM) { // ARCH_WFE(); //}
//OS_Start();
while(1) { ARCH_WFI(); } }
运行,
hisilicon # go 0x80000000 ## Starting application at 0x80000000 ...
RTOS SMP Cortex-A7*2 [v0.1.0 Oct 4 2020 17:01:51] [DBG]{ARCH_IrqUnmask() L335} enable irq 29 CPU#0: tick 1 CPU#0: tick 2 CPU#0: tick 3 CPU#0: tick 4 CPU#0: tick 5 CPU#0: tick 6 CPU#0: tick 7 CPU#0: tick 8 CPU#0: tick 9 CPU#0: tick 10 CPU#0: tick 11 CPU#0: tick 12 CPU#0: tick 13 CPU#0: tick 14 CPU#0: tick 15 CPU#0: tick 16 CPU#0: tick 17 CPU#0: tick 18 CPU#0: tick 19 CPU#0: tick 20