[커널 18차] 65주차
2022.08.20 22:22
timer 진행중
git : https://github.com/iamroot18/5.10/commit/db6e14048fc71d57f64c1633fb884ee502f91ffc
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index 88d20f04c64a..ae651007eca4 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -149,6 +149,18 @@ u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
BUG();
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - CNTFRQ_EL0, Counter-timer Frequency register를 읽는다.
+ * (arch timer에 사용한 주파수.)
+ * - Bits [63:32]
+ * Reserved, RES0.
+ *
+ * - Bits [31:0]
+ * Clock frequency. Indicates the system counter clock frequency, in Hz.
+ * The reset behavior of this field is:
+ * On a Warm reset, this field resets to an architecturally UNKNOWN value.
+ */
static inline u32 arch_timer_get_cntfrq(void)
{
return read_sysreg(cntfrq_el0);
@@ -175,6 +187,10 @@ static __always_inline u64 __arch_counter_get_cntpct_stable(void)
return cnt;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - read cntpct_el0
+ */
static __always_inline u64 __arch_counter_get_cntpct(void)
{
u64 cnt;
@@ -195,6 +211,13 @@ static __always_inline u64 __arch_counter_get_cntvct_stable(void)
return cnt;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - CNTVCT_EL0, Counter-timer Virtual Count register
+ * Holds the 64-bit virtual count value. The virtual count value is equal to the physical count
+ * value minus the virtual offset visible in CNTVOFF_EL2.
+ * - read cntvct_el0
+ */
static __always_inline u64 __arch_counter_get_cntvct(void)
{
u64 cnt;
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 49814ce8d2c6..45420232e35f 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -88,6 +88,58 @@ static inline unsigned long array_index_mask_nospec(unsigned long idx,
*
* https://lore.kernel.org/r/alpine.DEB.2.21.1902081950260.1662@nanos.tec.linutronix.de/
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - papago
+ * 카운터 읽기가 후속 메모리 배리어에 의한 순서를 위해 메모리 읽기와 동일하게 처리되는지
+ * 확인하십시오.
+ *
+ * 이 광기는 추측성 시스템 레지스터 읽기, 비순차적 메모리 액세스, 시퀀스 잠금 및
+ * Thomas Gleixner로 인해 발생했습니다.
+ * - eor %0, %1, %1 => 같은값 xor을 하면 결국 0.
+ * add x0, sp, %0 => sp + 0 = sp
+ * ldr xzr, [%0] => xzr에 sp가 가리키는 data를 load. 아무 일 안함.
+ *
+ * - git blame
+ * arm64: vdso: Avoid ISB after reading from cntvct_el0.
+ *
+ * We can avoid the expensive ISB instruction after reading the counter in the vDSO gettime
+ * functions by creating a fake address hazard against a dummy stack read, just like we do
+ * inside the kernel.
+ *
+ * - papgo
+ * arm64: vdso: cntvct_el0에서 읽은 후에는 ISB를 피하십시오.
+ *
+ * 커널 내부에서처럼 더미 스택 읽기에 대해 가짜 주소 위험을 생성하여 vDSO gettime 함수의
+ * 카운터를 읽은 후 값비싼 ISB 명령을 피할 수 있다.
+ *
+ * - git blame2
+ * arm64: arch_timer: Ensure counter register reads occur with seqlock held.
+ *
+ * When executing clock_gettime(), either in the vDSO or via a system call, we need to ensure
+ * that the read of the counter register occurs within the seqlock reader critical section.
+ * This ensures that updates to the clocksource parameters (e.g. the multiplier) are consistent
+ * with the counter value and therefore avoids the situation where time appears to go backwards
+ * across multiple reads.
+ *
+ * Extend the vDSO logic so that the seqlock critical section covers the read of the counter
+ * register as well as accesses to the data page. Since reads of the counter system registers
+ * are not ordered by memory barrier instructions, introduce dependency ordering from the counter
+ * read to a subsequent memory access so that the seqlock memory barriers apply to the counter
+ * access in both the vDSO and the system call paths.
+ *
+ * - papago
+ * arm64: arch_timer: 카운터 레지스터 읽기가 시퀀스를 누른 상태에서 수행되는지 확인합니다.
+ *
+ * vDSO에서 또는 시스템 호출을 통해 clock_gettime()을 실행할 때는 카운터 레지스터 읽기가 seqlock
+ * Reader critical 섹션 내에서 수행되도록 해야 합니다. 이렇게 하면 클럭 소스 매개 변수(예: 승수)에
+ * 대한 업데이트가 카운터 값과 일치하므로 여러 판독에서 시간이 거꾸로 가는 상황을 피할 수 있다.
+ *
+ * seqlock 중요 섹션이 카운터 레지스터 읽기와 데이터 페이지 액세스를 포함하도록 vDSO 논리를
+ * 확장합니다. 카운터 시스템 레지스터 읽기는 메모리 장벽 지침에 따라 정렬되지 않으므로 카운터
+ * 읽기부터 후속 메모리 액세스까지 종속성 순서를 도입하여 seqlock 메모리 장벽이 vDSO 및 시스템
+ * 호출 경로 모두에서 카운터 액세스에 적용되도록 합니다.
+ */
#define arch_counter_enforce_ordering(val) do { \
u64 tmp, _val = (val); \
\
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index be6d741d404c..41815b33fdb5 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -66,6 +66,15 @@ struct arch_timer {
static u32 arch_timer_rate __ro_after_init;
static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init;
+/*
+ * IAMROOT, 2022.08.20:
+ * - dts에는 다음과 같이 있다.
+ * interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, // Physical Secure
+ * <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, // Physical Non-Secure
+ * <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, // Virtual
+ * <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; // Hypervisor
+ *
+ */
static const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = {
[ARCH_TIMER_PHYS_SECURE_PPI] = "sec-phys",
[ARCH_TIMER_PHYS_NONSECURE_PPI] = "phys",
@@ -76,9 +85,25 @@ static const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = {
static struct clock_event_device __percpu *arch_timer_evt;
+/*
+ * IAMROOT, 2022.08.20:
+ * - kernel에서 사용할 timer.
+ */
static enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init = ARCH_TIMER_VIRT_PPI;
+
+/*
+ * IAMROOT, 2022.08.20:
+ * - clock을 끄는 기능의 지원여부. 절전등에서 사용한다.
+ * core가 정지.
+ */
static bool arch_timer_c3stop __ro_after_init;
static bool arch_timer_mem_use_virtual __ro_after_init;
+
+/*
+ * IAMROOT, 2022.08.20:
+ * - dts prop : arm,no-tick-in-suspend
+ * 절전시 interrupt on/off 여부.
+ */
static bool arch_counter_suspend_stop __ro_after_init;
#ifdef CONFIG_GENERIC_GETTIMEOFDAY
static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
@@ -166,6 +191,10 @@ static notrace u64 arch_counter_get_cntpct_stable(void)
return __arch_counter_get_cntpct_stable();
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - read cntpct
+ */
static notrace u64 arch_counter_get_cntpct(void)
{
return __arch_counter_get_cntpct();
@@ -176,6 +205,10 @@ static notrace u64 arch_counter_get_cntvct_stable(void)
return __arch_counter_get_cntvct_stable();
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - read cntvct
+ */
static notrace u64 arch_counter_get_cntvct(void)
{
return __arch_counter_get_cntvct();
@@ -200,6 +233,10 @@ static u64 arch_counter_read_cc(const struct cyclecounter *cc)
return arch_timer_read_counter();
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - !arch_counter_suspend_stop => flags CLOCK_SOURCE_SUSPEND_NONSTOP 추가
+ */
static struct clocksource clocksource_counter = {
.name = "arch_sys_counter",
.id = CSID_ARM_ARCH_COUNTER,
@@ -391,6 +428,12 @@ static u32 notrace sun50i_a64_read_cntv_tval_el0(void)
}
#endif
+/*
+ * IAMROOT, 2022.08.20:
+ * - Out of Line Counter.
+ * 하드웨어 이상으로 counter값이 순간적으로 튀는등 이상하게 변동되는경우가 있는데,
+ * 그것에 대한 방어코드.
+ */
#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);
EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
@@ -592,6 +635,11 @@ void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa
}
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - ool일 발생할수있는 arch일 경우 거기에 대한 방어처리를 한다.
+ * ool_workarounds 참고.
+ */
static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type type,
void *arg)
{
@@ -879,6 +927,12 @@ static void arch_counter_set_user_access(void)
arch_timer_set_cntkctl(cntkctl);
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - kernel이 현재 쓰는 timer가 ARCH_TIMER_PHYS_SECURE_PPI인데
+ * ARCH_TIMER_PHYS_NONSECURE_PPI가 설정되잇으면 true.
+ * - system이 secure상태인데 none-secure도 있으면 none-secure도 설정하기 위함.
+ */
static bool arch_timer_has_nonsecure_ppi(void)
{
return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI &&
@@ -921,6 +975,10 @@ static int arch_timer_starting_cpu(unsigned int cpu)
return 0;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - timer 유효성검사.
+ */
static int validate_timer_rate(void)
{
if (!arch_timer_rate)
@@ -937,6 +995,12 @@ static int validate_timer_rate(void)
* rate was probed first, and don't verify that others match. If the first node
* probed has a clock-frequency property, this overrides the HW register.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - 이미 설정되있으면 return.
+ * clock-frequency prop에 없으면 @rate를, 존재한다면 dts를 우선해서 사용한다.
+ * - 즉 dts에 있으면 dts, 아니면 bootloader에서 읽은걸 asrch_timer_rate로 사용한다.
+ */
static void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np)
{
/* Who has more than one independent system counter? */
@@ -951,6 +1015,15 @@ static void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np
pr_warn("frequency not available\n");
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - pc ubuntu(guest os)
+ * arch_timer: cp15 timer(s) running at 62.50MHz (virt).
+ * - rpi4
+ * arch_timer: cp15 timer(s) running at 54.00MHz (phys).
+ * - rpi4(guest os)
+ * arch_timer: cp15 timer(s) running at 54.00MHz (virt).
+ */
static void __init arch_timer_banner(unsigned type)
{
pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
@@ -1004,11 +1077,25 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(void)
return &arch_timer_kvm_info;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * @type arch_timers_present
+ */
static void __init arch_counter_register(unsigned type)
{
u64 start_count;
/* Register the CP15 based counter if we have one */
+/*
+ * IAMROOT, 2022.08.20:
+ * - wa(workaround) 는 고려안함.
+ *
+ * 1. type 에 CP15 존재
+ * - arm64, !hyp = arch_counter_get_cntvct
+ * - ppi = virt_ppi = arch_counter_get_cntvct
+ * - 그외(arm64가 아니거나 hyp mode) = arch_counter_get_cntpct
+ * 2. type 에 CP15 없음(MEM이라는뜻). = arch_counter_get_cntvct_mem
+ */
if (type & ARCH_TIMER_TYPE_CP15) {
u64 (*rd)(void);
@@ -1033,6 +1120,11 @@ static void __init arch_counter_register(unsigned type)
if (!arch_counter_suspend_stop)
clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
+
+/*
+ * IAMROOT, 2022.08.20:
+ * -
+ */
start_count = arch_timer_read_counter();
clocksource_register_hz(&clocksource_counter, arch_timer_rate);
cyclecounter.mult = clocksource_counter.mult;
@@ -1087,6 +1179,10 @@ static struct notifier_block arch_timer_cpu_pm_notifier = {
.notifier_call = arch_timer_cpu_pm_notify,
};
+/*
+ * IAMROOT, 2022.08.20:
+ * - notifier 등록
+ */
static int __init arch_timer_cpu_pm_init(void)
{
return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier);
@@ -1108,6 +1204,11 @@ static void __init arch_timer_cpu_pm_deinit(void)
}
#endif
+/*
+ * IAMROOT, 2022.08.20:
+ * - arch_timer_evt를 생성한다.
+ * - kernel timer의 percpu irq를 등록한다.
+ */
static int __init arch_timer_register(void)
{
int err;
@@ -1120,6 +1221,16 @@ static int __init arch_timer_register(void)
}
ppi = arch_timer_ppi[arch_timer_uses_ppi];
+
+/*
+ * IAMROOT, 2022.08.20:
+ * - cpu마다 있는 irq에 대해 irq를 등록한다.
+ * -
+ * ARCH_TIMER_VIRT_PPI : guest os용
+ * ARCH_TIMER_PHYS_NONSECURE_PPI : EL1에서 동작하는 linux kernel 용.
+ * ARCH_TIMER_PHYS_SECURE_PPI :
+ * ARCH_TIMER_HYP_PPI : EL2에서 동작하는 linux kernel 용.
+ */
switch (arch_timer_uses_ppi) {
case ARCH_TIMER_VIRT_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_virt,
@@ -1127,6 +1238,15 @@ static int __init arch_timer_register(void)
break;
case ARCH_TIMER_PHYS_SECURE_PPI:
case ARCH_TIMER_PHYS_NONSECURE_PPI:
+/*
+ * IAMROOT, 2022.08.20:
+ * - kernel이 none-secure
+ * arch_timer_evt등록.
+ * - kernel이 ARCH_TIMER_PHYS_SECURE_PPI 이면서 ARCH_TIMER_PHYS_NONSECURE_PPI가 없는상태.
+ * arch_timer_evt등록.
+ * - kernel이 ARCH_TIMER_PHYS_SECURE_PPI 이면서 ARCH_TIMER_PHYS_NONSECURE_PPI가 있는 상태.
+ * arch_timer_evt, arch_timer_handler_phys등록.
+ */
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
if (!err && arch_timer_has_nonsecure_ppi()) {
@@ -1156,6 +1276,10 @@ static int __init arch_timer_register(void)
goto out_unreg_notify;
/* Register and immediately configure the timer on the boot CPU */
+/*
+ * IAMROOT, 2022.08.20:
+ * - CPUHP_AP_ARM_ARCH_TIMER_STARTING로 on / off일때 각각의 callback 함수를 등록.
+ */
err = cpuhp_setup_state(CPUHP_AP_ARM_ARCH_TIMER_STARTING,
"clockevents/arm/arch_timer:starting",
arch_timer_starting_cpu, arch_timer_dying_cpu);
@@ -1217,12 +1341,20 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
{},
};
+/*
+ * IAMROOT, 2022.08.20:
+ * - CP15가 설정되있다면 MEM을, MEM이 설정되있다면 CP15를 확인하여 probing.
+ */
static bool __init arch_timer_needs_of_probing(void)
{
struct device_node *dn;
bool needs_probing = false;
unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
+/*
+ * IAMROOT, 2022.08.20:
+ * - CP15, MEM둘중 하나만 초기화 하기 위한것.
+ */
/* We have two timers, and both device-tree nodes are probed. */
if ((arch_timers_present & mask) == mask)
return false;
@@ -1231,6 +1363,16 @@ static bool __init arch_timer_needs_of_probing(void)
* Only one type of timer is probed,
* check if we have another type of timer node in device-tree.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - ARCH_TIMER_TYPE_CP15 지원.
+ * arm,armv7-timer-mem
+ *
+ * - ARCH_TIMER_TYPE_MEM 지원.
+ * arm,armv7-timer, arm,armv7-timer
+ *
+ * 나머지 한개에 대해서 probing을 요구.
+ */
if (arch_timers_present & ARCH_TIMER_TYPE_CP15)
dn = of_find_matching_node(NULL, arch_timer_mem_of_match);
else
@@ -1269,6 +1411,13 @@ static int __init arch_timer_common_init(void)
*
* Return: a suitable PPI type for the current system.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * 1. hyp mode : ARCH_TIMER_HYP_PPI
+ * 2. hyp mode disable. 이고 ARCH_TIMER_VIRT_PPI존재. : ARCH_TIMER_VIRT_PPI
+ * 3. arm64 : ARCH_TIMER_PHYS_NONSECURE_PPI
+ * 4. 그외 ARCH_TIMER_PHYS_SECURE_PPI
+ */
static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
{
if (is_kernel_in_hyp_mode())
@@ -1283,6 +1432,12 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
return ARCH_TIMER_PHYS_SECURE_PPI;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - ARCH_TIMER_VIRT_PPI에 해당하는 irq를 arch_timer_kvm_info.virtual_irq에 넣는다.
+ * 현재 kernel이 hyp mode면 ARCH_TIMER_PHYS_NONSECURE_PPI에 해당하는 irq를
+ * arch_timer_kvm_info.physical_irq에 넣는다.
+ */
static void __init arch_timer_populate_kvm_info(void)
{
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
@@ -1290,12 +1445,20 @@ static void __init arch_timer_populate_kvm_info(void)
arch_timer_kvm_info.physical_irq = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - ARCH_TIMER_TYPE_CP15 방식의 초기화 방법.
+ */
static int __init arch_timer_of_init(struct device_node *np)
{
int i, irq, ret;
u32 rate;
bool has_names;
+/*
+ * IAMROOT, 2022.08.20:
+ * - ARCH_TIMER_TYPE_CP15의 방식으로의 설정이 중복되서 호출됬는지 확인한다.
+ */
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("multiple nodes in dt, skipping\n");
return 0;
@@ -1305,6 +1468,22 @@ static int __init arch_timer_of_init(struct device_node *np)
has_names = of_property_read_bool(np, "interrupt-names");
+/*
+ * IAMROOT, 2022.08.20:
+ * - interrupt-names에 name이 있다면 name을 기준으로, 아니면 순서대로 irq 번호를 찾는다.
+ * 여기 찾는건 virq(virutal irq).
+ *
+ * - ex) interrupt-names 사용처 예제. dts/apple/t8103.dtsi
+ * timer {
+ * compatible = "arm,armv8-timer";
+ * interrupt-parent = <&aic>;
+ * interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt";
+ * interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
+ * <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>,
+ * <AIC_FIQ AIC_TMR_HV_PHYS IRQ_TYPE_LEVEL_HIGH>,
+ * <AIC_FIQ AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>;
+ * };
+ */
for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) {
if (has_names)
irq = of_irq_get_byname(np, arch_timer_ppi_names[i]);
@@ -1316,9 +1495,18 @@ static int __init arch_timer_of_init(struct device_node *np)
arch_timer_populate_kvm_info();
+/*
+ * IAMROOT, 2022.08.20:
+ * - arch timer hz를 cntfrq에서 읽어온다. 그 이후에 dts에 timer clock값이 존재하면, dts우선,
+ * 아니면 cntfrq에서 읽어온(bootloader가 세팅해준)값을 사용한다.
+ */
rate = arch_timer_get_cntfrq();
arch_timer_of_configure_rate(rate, np);
+/*
+ * IAMROOT, 2022.08.20:
+ * - always-on이 존재하면 arch_timer_c3stop을 disable.
+ */
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
/* Check for globally applicable workarounds */
@@ -1328,6 +1516,10 @@ static int __init arch_timer_of_init(struct device_node *np)
* If we cannot rely on firmware initializing the timer registers then
* we should use the physical timers instead.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - 현재 kernel이 사용할 timer의 종류를 구한다.
+ */
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
@@ -1340,6 +1532,10 @@ static int __init arch_timer_of_init(struct device_node *np)
}
/* On some systems, the counter stops ticking when in suspend. */
+/*
+ * IAMROOT, 2022.08.20:
+ * - 절전시 interrupt on/off여부를 dts에서 prop를 통해 읽어온다.
+ */
arch_counter_suspend_stop = of_property_read_bool(np,
"arm,no-tick-in-suspend");
@@ -1347,9 +1543,18 @@ static int __init arch_timer_of_init(struct device_node *np)
if (ret)
return ret;
+/*
+ * IAMROOT, 2022.08.20:
+ * - CP15가 위에서 설정되었고, MEM이 아직 설정안된상태에서 MEM이 dts에 있으면 return true로
+ * probe해야되는 상태. MEM probe에서 arch_timer_common_init을 호출할것이다.
+ */
if (arch_timer_needs_of_probing())
return 0;
+/*
+ * IAMROOT, 2022.08.20:
+ * - MEM을 probe할 필요없거나 둘다 초기화됬으면 arch_timer_common_init()을 호출한다.
+ */
return arch_timer_common_init();
}
TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
@@ -1464,6 +1669,41 @@ arch_timer_mem_frame_register(struct arch_timer_mem_frame *frame)
return 0;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - memory mapped 방식의 timer.
+ * ioremap으로 vmap으로 mapping하며 해당 memory를 register로 사용하는 방법.
+ *
+ * ex) dts에서 사용한 예. cp15방식의 timer와 동시에 사용하는것이 보인다.
+ * (qcom/ipq6018.dtsi)
+ *
+ * timer {
+ * compatible = "arm,armv8-timer";
+ * interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ * <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ * <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ * <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ * };
+ *
+ * timer@b120000 {
+ * #address-cells = <2>;
+ * #size-cells = <2>;
+ * ranges;
+ * compatible = "arm,armv7-timer-mem";
+ * reg = <0x0 0x0b120000 0x0 0x1000>;
+ * clock-frequency = <19200000>;
+ *
+ * frame@b120000 {
+ * frame-number = <0>;
+ * interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ * <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ * reg = <0x0 0x0b121000 0x0 0x1000>,
+ * <0x0 0x0b122000 0x0 0x1000>;
+ * };
+ * ....
+ * }
+ *
+ */
static int __init arch_timer_mem_of_init(struct device_node *np)
{
struct arch_timer_mem *timer_mem;
diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c
index a50ab5c2154f..f7b32d7f4a26 100644
--- a/drivers/clocksource/bcm_kona_timer.c
+++ b/drivers/clocksource/bcm_kona_timer.c
@@ -41,6 +41,10 @@ struct kona_bcm_timers {
static struct kona_bcm_timers timers;
+/*
+ * IAMROOT, 2022.08.20:
+ * - dts나 bootloader에서 읽어온 arch timer hz. dts가 우선된다.
+ */
static u32 arch_timer_rate;
/*
diff --git a/drivers/clocksource/timer-probe.c b/drivers/clocksource/timer-probe.c
index b7860bc0db4b..07c5cb275004 100644
--- a/drivers/clocksource/timer-probe.c
+++ b/drivers/clocksource/timer-probe.c
@@ -8,11 +8,20 @@
#include <linux/of.h>
#include <linux/clocksource.h>
+/*
+ * IAMROOT, 2022.08.20:
+ * - compile time에 등록된 timer들.
+ * ex) TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
+ */
extern struct of_device_id __timer_of_table[];
static const struct of_device_id __timer_of_table_sentinel
__used __section("__timer_of_table_end");
+/*
+ * IAMROOT, 2022.08.20:
+ * -
+ */
void __init timer_probe(void)
{
struct device_node *np;
@@ -21,6 +30,25 @@ void __init timer_probe(void)
unsigned timers = 0;
int ret;
+/*
+ * IAMROOT, 2022.08.20:
+ * - compile time에 __timer_of_table에 등록된 driver들을 순회하며 dts와
+ * 매칭하며 ok된것들에 대해서 init함수를 호출한다
+ * ex) TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
+ * 로 등록됬으면 arch_timer_of_init을 호출한다.
+ *
+ * ex) dts 예제
+ *
+ * timer {
+ * compatible = "arm,armv8-timer";
+ * interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, // Physical Secure
+ * <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, // Physical Non-Secure
+ * <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, // Virtual
+ * <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; // Hypervisor
+ * interrupt-parent = <&gic>;
+ * arm,no-tick-in-suspend;
+ * };
+ */
for_each_matching_node_and_match(np, __timer_of_table, &match) {
if (!of_device_is_available(np))
continue;
@@ -38,6 +66,10 @@ void __init timer_probe(void)
timers++;
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - acpi 호출.
+ */
timers += acpi_probe_device_table(timer);
if (!timers)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 352e14b007e7..c9b3303c23aa 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -384,6 +384,10 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource);
* -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
* of any other failure.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - @index에 해당하는 irq번호를 가져온다.
+ */
int of_irq_get(struct device_node *dev, int index)
{
int rc;
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 73c7139c866f..300020ab4dca 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -27,6 +27,12 @@ enum arch_timer_reg {
ARCH_TIMER_REG_TVAL,
};
+/*
+ * IAMROOT, 2022.08.20:
+ * - PPI : private peri irq. cpu당 개별 irq 지원.
+ * - ARCH_TIMER_PHYS_SECURE_PPI
+ * arm의 경우 arm,cpu-registers-not-fw-configured prop가 있으면 사용한다.
+ */
enum arch_timer_ppi_nr {
ARCH_TIMER_PHYS_SECURE_PPI,
ARCH_TIMER_PHYS_NONSECURE_PPI,
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 1d42d4b17327..2b8c839c6768 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -241,6 +241,10 @@ static inline int __clocksource_register(struct clocksource *cs)
return __clocksource_register_scale(cs, 1, 0);
}
+/*
+ * IAMROOT, 2022.08.20:
+ * -
+ */
static inline int clocksource_register_hz(struct clocksource *cs, u32 hz)
{
return __clocksource_register_scale(cs, 1, hz);
@@ -261,6 +265,10 @@ static inline void __clocksource_update_freq_khz(struct clocksource *cs, u32 khz
__clocksource_update_freq_scale(cs, 1000, khz);
}
+/*
+ * IAMROOT, 2022.08.20:
+ * - arm은 없음.
+ */
#ifdef CONFIG_ARCH_CLOCKSOURCE_INIT
extern void clocksource_arch_init(struct clocksource *cs);
#else
@@ -279,6 +287,10 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
extern int clocksource_i8253_init(void);
+/*
+ * IAMROOT, 2022.08.20:
+ * - __timer_of_table에 등록된다.
+ */
#define TIMER_OF_DECLARE(name, compat, fn) \
OF_DECLARE_1_RET(timer, name, compat, fn)
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index b8a14d2fb5ba..d7082bc17fc4 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -43,16 +43,49 @@
* reduce the conversion accuracy by choosing smaller mult and shift
* factors.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * ex) from = 19200000, to = 10^9, maxsec = 600
+ * - sftacc 계산
+ * 600 * 19200000 = 0x2_AEA5_4000 => shift32 => 0x2
+ * 두번 loop를 돌면 sftacc = 30가 된다.
+ */
void
clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
{
u64 tmp;
+/*
+ * IAMROOT, 2022.08.20:
+ * - 정확도는 최대 32bit.
+ */
u32 sft, sftacc= 32;
/*
* Calculate the shift factor which is limiting the conversion
* range:
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * 63.. 55 0
+ * | unusable | counter |
+ *
+ * | | empty | sec(최대600) | freq |
+ *
+ * 여기선 정확도용으로 사용할 bit를 계산한다.
+ *
+ * | 정확도용 | sec(최대600) | freq |
+ * ^
+ * 이 부분일거같은 bit를 찾는것.
+ *
+ * | 정확도용 | sec(최대600) | freq |
+ * <----------- sftacc ------> <------- maxsec * from ---------------->
+ * ^
+ * ex) from = 19200000, to = 10^9, maxsec = 600, sftacc = 30
+ *
+ * | 정확도용 | sec(최대600) | freq |
+ * <----------- sftacc ------> <------- maxsec * from ---------------->
+ * 30 bits ^ 34bit
+ */
tmp = ((u64)maxsec * from) >> 32;
while (tmp) {
tmp >>=1;
@@ -63,6 +96,24 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
* Find the conversion shift/mult pair which has the best
* accuracy and fits the maxsec conversion range:
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - from * mult >> shift = to의 개념에서 mult, shift값을 구한다.
+ * tmp = (to << sft + from / 2) / from
+ *
+ * - sftacc 내에서 처리될수있는 mult, shift값을 계산한다.
+ * - from / 2는 나머지를 고려해서, do_div(mult, from)를 할때 정확성을 조금 올리는것.
+ * - from으로 위애서 sftacc(정확도)를 구하고, sftacc내의 범위에서 to값의 최종 정확도를 shift
+ * 한값이 들어오는지 계산하여 mult, sft값을 구한다.
+ *
+ * ex) from = 19200000, to = 10^9, maxsec = 600, sftacc = 30
+ * sft = 24이면
+ * tmp = 1000000000 << 24 = 16777216000000000
+ * tmp += 9600000
+ * tmp = do_div(16777216000000000, 19200000) = 873813333 = 0x3415_5555
+ * tmp >> sftasce = 0x3415_5555 >> 30 == 0
+ * mult = 0x3415_5555, shift = 24가 된다.
+ */
for (sft = 32; sft > 0; sft--) {
tmp = (u64) to << sft;
tmp += from / 2;
@@ -1046,7 +1097,24 @@ void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq
* clocksource with mask >= 40-bit and f >= 4GHz. That maps to
* ~ 0.06ppm granularity for NTP.
*/
+
+/*
+ * IAMROOT, 2022.08.20:
+ * - papago
+ * 둘러싸기 전에 실행할 수 있는 최대 시간(초)을 계산합니다. 마스크가 32비트보다 큰 클록
+ * 소스의 경우 좋은 변환 정밀도를 갖기 위해 최대 절전 시간을 제한해야 합니다. 10분은 여전히
+ * 적당한 양입니다. 그 결과 마스크 >= 40비트 및 f >= 4GHz인 클록 소스에 대해 시프트 값이 24가
+ * 됩니다. 이는 NTP의 경우 ~ 0.06ppm 단위로 매핑됩니다.
+ */
sec = cs->mask;
+/*
+ * IAMROOT, 2022.08.20:
+ * - sec = sec / freq / scale
+ * ex) cs->mask = CLOCKSOURCE_MASK(56), freq = 19200000, scale = 1
+ * sec = 0xff_ffff_ffff_ffff / 19200000 = 3752999689 => clamp => 600
+ *
+ * clamp로 10분을 한계로 두고 정확도를 높이는 개념.
+ */
do_div(sec, freq);
do_div(sec, scale);
if (!sec)
@@ -1054,6 +1122,12 @@ void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq
else if (sec > 600 && cs->mask > UINT_MAX)
sec = 600;
+/*
+ * IAMROOT, 2022.08.20:
+ * - sec * scale시간을 한계로 freq -> NSEC_PER_SEC / scale이 되기 위한 mult, shift를 계산한다.
+ * ex) clocksource_counter에서 mask = CLOCKSOURCE_MASK(56)
+ * ex) cs->mask = CLOCKSOURCE_MASK(56), freq = 19200000, scale = 1, sec = 600
+ */
clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
NSEC_PER_SEC / scale, sec * scale);
}
@@ -1115,6 +1189,10 @@ EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale);
* This *SHOULD NOT* be called directly! Please use the
* clocksource_register_hz() or clocksource_register_khz helper functions.
*/
+/*
+ * IAMROOT, 2022.08.20:
+ * - scale * freq = 실제 freq
+ */
int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
{
unsigned long flags;
@@ -1123,6 +1201,11 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
if (WARN_ON_ONCE((unsigned int)cs->id >= CSID_MAX))
cs->id = CSID_GENERIC;
+
+/*
+ * IAMROOT, 2022.08.20:
+ * ex) VDSO_CLOCKMODE_NONE, VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT
+ */
if (cs->vdso_clock_mode < 0 ||
cs->vdso_clock_mode >= VDSO_CLOCKMODE_MAX) {
pr_warn("clocksource %s registered with invalid VDSO mode %d. Disabling VDSO support.\n",
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 631 |
148 | [커널 17차] 103주차 | ㅇㅇㅇ | 2022.08.28 | 35 |
147 | [커널 18차] 66주차 | kkr | 2022.08.27 | 79 |
146 | [커널 17차] 101~102주차 | ㅇㅇㅇ | 2022.08.21 | 47 |
» | [커널 18차] 65주차 | kkr | 2022.08.20 | 28 |
144 | [커널 18차] 64주차 | kkr | 2022.08.13 | 75 |
143 | [커널 17차] 100주차 [1] | ㅇㅇㅇ | 2022.08.06 | 100 |
142 | [커널 18차] 63주차 | kkr | 2022.08.06 | 102 |
141 | [커널 17차] 99주차 | ㅇㅇㅇ | 2022.07.31 | 35 |
140 | [커널 18차] 62주차 | kkr | 2022.07.30 | 26 |
139 | [커널 17차] 97~98주차 | ㅇㅇㅇ | 2022.07.24 | 52 |
138 | [커널 18차] 61주차 | kkr | 2022.07.23 | 114 |
137 | [커널 18차] 60주차 | kkr | 2022.07.16 | 133 |
136 | [커널 17차] 95~96주차 | ㅇㅇㅇ | 2022.07.10 | 108 |
135 | [커널 18차] 59주차 | kkr | 2022.07.09 | 128 |
134 | [커널 19차] 8주차 | kanlee | 2022.07.02 | 160 |
133 | [커널 19차] 7주차 | kanlee | 2022.07.02 | 97 |
132 | [커널 19차] 6주차 | kanlee | 2022.07.02 | 42 |
131 | [커널 19차] 5주차 | kanlee | 2022.07.02 | 38 |
130 | [커널 19차] 4주차 | kanlee | 2022.07.02 | 106 |
129 | [커널 18차] 57주차 | kkr | 2022.06.25 | 129 |
.