이 코드는 어떤 문제를 푸나요?
지금이 몇 시인지 읽는 장치와 나중에 깨워 달라고 예약하는 장치는 목적이 다릅니다. arm64 architected timer, x86 TSC와 event 장치, RISC-V time counter와 SBI/SSTC를 구분합니다. 대표로 RISC-V의 다음 timer event 설정 함수를 읽습니다.
읽을 범위: v6.18.37 · drivers/clocksource/timer-riscv.c · riscv_clock_next_event 46–63행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
clocksource
시간의 경과를 계산할 카운터를 제공합니다.
clockevent
미래의 특정 시점에 인터럽트를 발생시키도록 예약하는 역할입니다.
delta
현재 카운터에서 얼마 뒤인지를 나타내는 tick 수입니다. 아래에서 절대 비교값 next_tval로 바뀝니다.
처음 읽을 때
현재 카운터가 1000이고 delta가 50이면 비교값은 1050이라는 예를 따라가십시오.
더 깊이 살펴볼 때
RV32에서 비교 레지스터를 여러 번 쓰는 순서와 SBI 호출 비용을 비교하십시오.
그림으로 보는 변화

1. 절대 시각 계산
현재 counter에 delta를 더합니다.
화살표는 tick 단위 수치 계산이며 nanosecond 변환이 아닙니다.
2. 지원 방식 선택
SSTC가 있으면 CSR을 쓰고 없으면 SBI에 요청합니다.
조건 분기는 CPU·펌웨어가 제공하는 인터페이스 차이입니다.
3. 미래 인터럽트 대기
설정한 비교값에 도달하면 timer 경로가 동작합니다.
설정 함수의 return과 실제 인터럽트 발생은 다른 시점입니다.
riscv_clock_next_event를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
static int riscv_clock_next_event(unsigned long delta,
struct clock_event_device *ce)
{
u64 next_tval = get_cycles64() + delta;
if (static_branch_likely(&riscv_sstc_available)) {
#if defined(CONFIG_32BIT)
csr_write(CSR_STIMECMP, ULONG_MAX);
csr_write(CSR_STIMECMPH, next_tval >> 32);
csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF);
#else
csr_write(CSR_STIMECMP, next_tval);
#endif
} else
sbi_set_timer(next_tval);
return 0;
}static int riscv_clock_next_event(unsigned long delta,현재 시점에서 delta tick 뒤에 이벤트를 발생시키도록 요청받는 clockevent 콜백입니다.
struct clock_event_device *ce)이 콜백을 호출한 clockevent 장치 서술자를 받습니다. 이 구현 본문에서는 ce를 직접 사용하지 않습니다.
u64 next_tval = get_cycles64() + delta;현재 64비트 카운터와 상대 delta를 더해 timer 비교기에 쓸 절대 tick 값을 만듭니다.
if (static_branch_likely(&riscv_sstc_available)) {SSTC 직접 접근이 가능한 것으로 초기화되어 있는지 static key로 확인합니다.
#if defined(CONFIG_32BIT)32비트 커널에서는 64비트 비교값을 두 CSR로 나눠 쓰는 코드를 선택합니다.
csr_write(CSR_STIMECMP, ULONG_MAX);낮은 절반을 우선 최대값으로 만들어 중간 상·하위 조합 때문에 원치 않는 만료가 발생할 위험을 줄입니다.
csr_write(CSR_STIMECMPH, next_tval >> 32);목표 비교값의 상위 32비트를 STIMECMPH에 기록합니다.
csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF);최종 하위 32비트를 STIMECMP에 기록하여 두 부분을 완성합니다.
#else64비트 커널의 대안 코드가 시작됩니다.
csr_write(CSR_STIMECMP, next_tval);64비트 CSR 한 번의 쓰기로 전체 비교값을 설정합니다.
#endif빌드 시 32비트/64비트 구분의 끝입니다.
} elseSSTC가 없는 런타임 조건에서는 다음 펌웨어 경로로 이어집니다.
sbi_set_timer(next_tval);SBI를 통해 펌웨어에 절대 timer 값을 설정해 달라고 요청합니다. S-mode가 CSR에 직접 쓰는 경로와 구분합니다.
return 0;이 콜백의 설정 요청을 완료했다는 0을 반환합니다. timer 인터럽트가 이미 발생했다는 뜻은 아닙니다.
함께 생각해 볼 질문
delta는 항상 나노초입니까?
아닙니다. 이 함수는 clockevent 계층에서 받은 카운터 tick 기준 값을 사용합니다.
SSTC가 없으면 timer를 못 씁니까?
이 경로는 SBI timer 요청으로 연결합니다.
RV32에서 하위 값을 먼저 최대값으로 쓰는 이유는 무엇입니까?
상·하위를 갱신하는 중간 값 때문에 원치 않는 즉시 만료가 발생하는 위험을 줄이기 위한 순서입니다.
출처와 읽은 범위
Linux stable v6.18.37 · drivers/clocksource/timer-riscv.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
