# Timer와 clocksource: architected timer, TSC와 RISC-V time

v6.18.37 / drivers/clocksource/timer-riscv.c

지금이 몇 시인지 읽는 장치와 나중에 깨워 달라고 예약하는 장치는 목적이 다릅니다. arm64 architected timer, x86 TSC와 event 장치, RISC-V time counter와 SBI/SSTC를 구분합니다. 대표로 RISC-V의 다음 timer event 설정 함수를 읽습니다.

## riscv_clock_next_event

```c

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;
}

```

### 46행

```c

static int riscv_clock_next_event(unsigned long delta,

```

현재 시점에서 delta tick 뒤에 이벤트를 발생시키도록 요청받는 clockevent 콜백입니다.

### 47행

```c

		struct clock_event_device *ce)

```

이 콜백을 호출한 clockevent 장치 서술자를 받습니다. 이 구현 본문에서는 ce를 직접 사용하지 않습니다.

### 49행

```c

	u64 next_tval = get_cycles64() + delta;

```

현재 64비트 카운터와 상대 delta를 더해 timer 비교기에 쓸 절대 tick 값을 만듭니다.

### 51행

```c

	if (static_branch_likely(&riscv_sstc_available)) {

```

SSTC 직접 접근이 가능한 것으로 초기화되어 있는지 static key로 확인합니다.

### 52행

```c

#if defined(CONFIG_32BIT)

```

32비트 커널에서는 64비트 비교값을 두 CSR로 나눠 쓰는 코드를 선택합니다.

### 53행

```c

		csr_write(CSR_STIMECMP, ULONG_MAX);

```

낮은 절반을 우선 최대값으로 만들어 중간 상·하위 조합 때문에 원치 않는 만료가 발생할 위험을 줄입니다.

### 54행

```c

		csr_write(CSR_STIMECMPH, next_tval >> 32);

```

목표 비교값의 상위 32비트를 STIMECMPH에 기록합니다.

### 55행

```c

		csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF);

```

최종 하위 32비트를 STIMECMP에 기록하여 두 부분을 완성합니다.

### 56행

```c

#else

```

64비트 커널의 대안 코드가 시작됩니다.

### 57행

```c

		csr_write(CSR_STIMECMP, next_tval);

```

64비트 CSR 한 번의 쓰기로 전체 비교값을 설정합니다.

### 58행

```c

#endif

```

빌드 시 32비트/64비트 구분의 끝입니다.

### 59행

```c

	} else

```

SSTC가 없는 런타임 조건에서는 다음 펌웨어 경로로 이어집니다.

### 60행

```c

		sbi_set_timer(next_tval);

```

SBI를 통해 펌웨어에 절대 timer 값을 설정해 달라고 요청합니다. S-mode가 CSR에 직접 쓰는 경로와 구분합니다.

### 62행

```c

	return 0;

```

이 콜백의 설정 요청을 완료했다는 0을 반환합니다. timer 인터럽트가 이미 발생했다는 뜻은 아닙니다.

