[커널 18차] 75주차

2022.10.29 22:18

kkr 조회 수:40

gic 등록 진행중

 

git : https://github.com/iamroot18/5.10/commit/551fc869843541a668f63bc5871134e6dfc9e436

 

diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 45420232e35f..e1c79406d464 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -39,6 +39,12 @@
 #define csdb()        asm volatile("hint #20" : : : "memory")
 
 #ifdef CONFIG_ARM64_PSEUDO_NMI
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - ICC_CTLR_EL1_PMHE_MASK가 set이면 enable되서 dsb(sy)이 동작할것이다.
+ *   gic_enable_nmi_support() 참고
+ */
 #define pmr_sync()                        \
     do {                            \
         extern struct static_key_false gic_pmr_sync;    \
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 1a9a26db58c8..61617c32301e 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -42,6 +42,24 @@
  * in the priority mask, it indicates that PSR.I should be set and
  * interrupt disabling temporarily does not rely on IRQ priorities.
  */
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   인터럽트를 마스크/언마스크하는 데 사용되는 PMR 값입니다. 
+ *
+ *   GIC 우선순위 마스킹은 다음과 같이 작동합니다.
+ *   IRQ의 우선순위가 PMR에 있는 값보다 높은 값이면 해당 IRQ는 마스킹됩니다.
+ *   PMR 값을 낮추는 것은 더 많은 IRQ를 마스킹하는 것을 의미합니다
+ *   (또는 적어도 동일한 IRQ가 마스킹된 상태로 유지됨). 
+ *
+ *   인터럽트를 마스크하기 위해 PMR의 최상위 비트를 지웁니다. 
+ *
+ *   일부 코드 섹션은 자동으로 PSR.I로 다시 전환하거나 우선 순위 마스킹을 사용하지 않도록
+ *   명시적으로 요구합니다. 비트 GIC_PRIO_PSR_I_SET이 우선 순위 마스크에 포함되어 있으면
+ *   PSR.I가 설정되어야 하고 일시적으로 인터럽트 비활성화가 IRQ 우선 순위에 의존하지
+ *   않음을 나타냅니다.
+ */
 #define GIC_PRIO_IRQON            0xe0
 #define __GIC_PRIO_IRQOFF        (GIC_PRIO_IRQON & ~0x80)
 #define __GIC_PRIO_IRQOFF_NS        0xa0
@@ -50,18 +68,38 @@
 
 /*
  * IAMROOT, 2022.10.08:
- * priority low
- *               0xff
- *               ..
- * 0b1110_0000   0xe0 enable (0b1110_0000)
- *               
- * 0b1010_0000   0xa0 normal irq(GICD_INT_DEF_PRI)
- *               
- * 0b0110_0000   0x60 disable   
- *               ..           ^
- *               ..           | disalbe시 이쪽만 interrupt를 부분적으로 허용한다.
- *               0x00         v
- * priority high     
+ * - two security, non-secure, kernel fiq 제어권있음     | secure 에서 보는 관점.
+ *  priority low 
+ *                0xff
+ *                ..
+ *  0b1110_0000   0xe0 enable (0b1110_0000)               0b1111_0000 0xf0
+ *                             ^
+ *                             | 이 부분을 dsiable
+ *                             v
+ *  0b1010_0000   0xa0 normal irq(GICD_INT_DEF_PRI)       0b1101_0000 0xd0
+ *  0b1010_0000   0xa0 disable (__GIC_PRIO_IRQOFF_NS) 
+ *                ..           |
+ *                ..           | disalbe시 이쪽만
+ *                ..           | interrupt를 부분적으로
+ *                ..           | 허용한다.
+ *                0x00         v
+ * priority high  priority high     
+ *
+ * - single security or
+ *   two security, non-secure, kenrel fiq 제어권 없음.
+ *  priority low 
+ *                0xff
+ *                ..
+ *  0b1110_0000   0xe0 enable (0b1110_0000)
+ *                ..
+ *  0b1010_0000   0xa0 normal irq(GICD_INT_DEF_PRI)
+ *                ..
+ *  0b0110_0000   0x60 disable (__GIC_PRIO_IRQOFF)
+ *                ..           ^ disalbe시 이쪽만
+ *                ..           | interrupt를 부분적으로
+ *                ..           | 허용한다.
+ *                0x00         v
+ * priority high  priority high     
  */
 #define GIC_PRIO_IRQOFF                            \
     ({                                \
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index fcd5a80a5e58..d979405d9f98 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -1028,6 +1028,10 @@ static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
     __ipi_send_mask(ipi_desc[ipinr], target);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - nr_ipi 만큼 current cpu에 대한 ipi irq enable.
+ */
 static void ipi_setup(int cpu)
 {
     int i;
@@ -1055,6 +1059,7 @@ static void ipi_teardown(int cpu)
 /*
  * IAMROOT, 2022.10.15:
  * - IPI(inter-processor interrupts)
+ * - ipi_handler로 handelr등록후 current cpu에 대해서 ipi 개수만큼 irq enable한다.
  */
 void __init set_smp_ipi_range(int ipi_base, int n)
 {
@@ -1068,6 +1073,19 @@ void __init set_smp_ipi_range(int ipi_base, int n)
  */
     nr_ipi = min(n, NR_IPI);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - nr_ipi 개수만큼 irq_base + i irq를 설정한다.
+ *
+ * - irq 흐름.
+ *   vector
+ *     v
+ *   chip handler
+ *     v
+ *   flow handler
+ *     v
+ *   irq_handler <--- ipi_handler
+ */
     for (i = 0; i < nr_ipi; i++) {
         int err;
 
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 6428d0ea11c9..8f1445bdb67b 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -158,6 +158,10 @@ EXPORT_SYMBOL(gic_nonsecure_priorities);
     })
 
 /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic_enable_nmi_support()에서 gic_data.ppi_nr개수만큼 초기화된다. 
+ */
 static refcount_t *ppi_nmi_refs;
 
 static struct gic_kvm_info gic_v3_kvm_info __initdata;
@@ -616,6 +620,10 @@ static void gic_irq_set_prio(struct irq_data *d, u8 prio)
     writeb_relaxed(prio, base + offset + index);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @hwirq로 ppi index를 구해온다. ppi가 아닐경우 unreachable.
+ */
 static u32 __gic_get_ppi_index(irq_hw_number_t hwirq)
 {
     switch (__get_intid_range(hwirq)) {
@@ -1340,6 +1348,14 @@ static void gic_update_rdist_properties(void)
 }
 
 /* Check whether it's single security state view */
+/*
+ * IAMROOT, 2022.10.29:
+ * return true : security disable
+ *        false : security enable
+ *
+ * - DS.0 == two security
+ * - DS.1 == single security
+ */
 static inline bool gic_dist_security_disabled(void)
 {
     return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
@@ -1723,7 +1739,7 @@ static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 
 /*
  * IAMROOT, 2022.10.15:
- * - 
+ * - sgi irq 설정.
  */
 static void __init gic_smp_init(void)
 {
@@ -1842,10 +1858,23 @@ static int gic_retrigger(struct irq_data *data)
 }
 
 #ifdef CONFIG_CPU_PM
+/*
+ * IAMROOT, 2022.10.29:
+ * - 절전 해제, 진입, security 상태에 따라 gic 설정.
+ */
 static int gic_cpu_pm_notifier(struct notifier_block *self,
                    unsigned long cmd, void *v)
 {
+/*
+ * IAMROOT, 2022.10.29:
+ * - CPU_PM_EXIT -> 절전 해제
+ * - CPU_PM_ENTER -> 절전
+ */
     if (cmd == CPU_PM_EXIT) {
+/*
+ * IAMROOT, 2022.10.29:
+ * - single이면 kernel이 제어.
+ */
         if (gic_dist_security_disabled())
             gic_enable_redist(true);
         gic_cpu_sys_reg_init();
@@ -1860,6 +1889,10 @@ static struct notifier_block gic_cpu_pm_notifier_block = {
     .notifier_call = gic_cpu_pm_notifier,
 };
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic에 대한 pm을 등록한다.
+ */
 static void gic_cpu_pm_init(void)
 {
     cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
@@ -1869,6 +1902,10 @@ static void gic_cpu_pm_init(void)
 static inline void gic_cpu_pm_init(void) { }
 #endif /* CONFIG_CPU_PM */
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - guest os or hyp가 없을때.
+ */
 static struct irq_chip gic_chip = {
     .name            = "GICv3",
     .irq_mask        = gic_mask_irq,
@@ -1887,6 +1924,10 @@ static struct irq_chip gic_chip = {
                   IRQCHIP_MASK_ON_SUSPEND,
 };
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - eoimode1 (hypmode 운영)
+ */
 static struct irq_chip gic_eoimode1_chip = {
     .name            = "GICv3",
     .irq_mask        = gic_eoimode1_mask_irq,
@@ -2028,6 +2069,10 @@ static int gic_irq_domain_translate(struct irq_domain *d,
         case GIC_IRQ_TYPE_LPI:    /* LPI */
             *hwirq = fwspec->param[1];
             break;
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic_populate_ppi_partitions() 참고
+ */
         case GIC_IRQ_TYPE_PARTITION:
             *hwirq = fwspec->param[1];
             if (fwspec->param[1] >= 16)
@@ -2115,6 +2160,22 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
     }
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - param, range등의 값 검사.
+ * - 통과 조건.
+ *   1. ppi_desc가 존재
+ *   2. fwnode가 of_node 측이여야된다.
+ *   3. param이 4개이상이고 param[3]이 NULL이 아니여야 된다.
+ *   4. range가 ppi류여야 된다.
+ *
+ * ex) dts(rk3399.dtsi)
+ * pmu_a53 {
+ *        compatible = "arm,cortex-a53-pmu";
+ *        interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster0>;
+ * }
+ * 마지막엔 반드시 연결된 cluster phandle이 등록되있다.
+ */
 static bool fwspec_is_partitioned_ppi(struct irq_fwspec *fwspec,
                       irq_hw_number_t hwirq)
 {
@@ -2136,6 +2197,14 @@ static bool fwspec_is_partitioned_ppi(struct irq_fwspec *fwspec,
     return true;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * @return 1 success. 0 false.
+ *
+ * - @fwspec와 @d가 매칭이 되는지 검사한다.
+ * - @d, @fwspec으로 hwirq, type을 구하고, @d가 해당 hwriq의
+ *   ppi parition domain인지 검사한다.
+ */
 static int gic_irq_domain_select(struct irq_domain *d,
                  struct irq_fwspec *fwspec,
                  enum irq_domain_bus_token bus_token)
@@ -2155,6 +2224,10 @@ static int gic_irq_domain_select(struct irq_domain *d,
     if (WARN_ON_ONCE(ret))
         return 0;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - domain이 gic_data.domain이면 true로 인정한다.
+ */
     if (!fwspec_is_partitioned_ppi(fwspec, hwirq))
         return d == gic_data.domain;
 
@@ -2162,6 +2235,10 @@ static int gic_irq_domain_select(struct irq_domain *d,
      * If this is a PPI and we have a 4th (non-null) parameter,
      * then we need to match the partition domain.
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - 위에서 true로 왔을경우 hwirq->ppi->idx->partition domain으로 얻어온다.
+ */
     ppi_idx = __gic_get_ppi_index(hwirq);
     return d == partition_get_domain(gic_data.ppi_descs[ppi_idx]);
 }
@@ -2177,6 +2254,10 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
     .select = gic_irq_domain_select,
 };
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - hwirq에 partition id를 얻어온다. type은 IRQ_NONE
+ */
 static int partition_domain_translate(struct irq_domain *d,
                       struct irq_fwspec *fwspec,
                       unsigned long *hwirq,
@@ -2190,14 +2271,26 @@ static int partition_domain_translate(struct irq_domain *d,
     if (!gic_data.ppi_descs)
         return -ENOMEM;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - cluster phandle.
+ */
     np = of_find_node_by_phandle(fwspec->param[3]);
     if (WARN_ON(!np))
         return -EINVAL;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - hwirq(ppi_intid), type구해오고
+ */
     ret = gic_irq_domain_translate(d, fwspec, &ppi_intid, type);
     if (WARN_ON_ONCE(ret))
         return 0;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - ppi_descs에서 partition id를 얻어온다.
+ */
     ppi_idx = __gic_get_ppi_index(ppi_intid);
     ret = partition_translate_id(gic_data.ppi_descs[ppi_idx],
                      of_node_to_fwnode(np));
@@ -2210,6 +2303,11 @@ static int partition_domain_translate(struct irq_domain *d,
     return 0;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - ppi의 경우 parititon을 만들시(partition_create_desc()) alloc, free ops에
+ *   partition_domain_alloc, partition_domain_free가 추가된다.
+ */
 static const struct irq_domain_ops partition_domain_ops = {
     .translate = partition_domain_translate,
     .select = gic_irq_domain_select,
@@ -2288,6 +2386,10 @@ static const struct gic_quirk gic_quirks[] = {
     }
 };
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - ppi_nmi_refs를 생성하고 nmi를 enable한다.
+ */
 static void gic_enable_nmi_support(void)
 {
     int i;
@@ -2307,6 +2409,14 @@ static void gic_enable_nmi_support(void)
      * set PMHE. The only reason to have it set is if EL3 requires it
      * (and we can't change it).
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - PMHE
+ *   Priority Mask Hint Enable. Controls whether the priority mask register is used
+ *   as a hint for interrupt distribution:
+ * - PMHE is set -> enable pmr -> sync(dsb(sy))가 필요하다는 뜻.
+ *   pmr_sync()참고
+ */
     if (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK)
         static_branch_enable(&gic_pmr_sync);
 
@@ -2340,11 +2450,57 @@ static void gic_enable_nmi_support(void)
      * be in the non-secure range, we use a different PMR value to mask IRQs
      * and the rest of the values that we use remain unchanged.
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   GIC에서 우선 순위 값을 사용하는 방법은 다음 두 가지 사항에 따라 다릅니다.
+ *   GIC의 보안 상태(GICD_CTRL.DS 비트에 의해 제어됨) 및 그룹 0 인터럽트가
+ *   FIQ(SCR_EL3.FIQ 비트에 의해 제어됨)로 비보안 세계에서 Linux에 전달될 수 있는 경우.
+ *   이는 ICC_PMR_EL1 레지스터와 소프트웨어가 인터럽트에 할당하는 우선 순위에 영향을
+ *   줍니다.
+ *
+ *                  el3에서 FIQ를
+ *                  받는지의 여부
+ *   GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
+ *   -----------------------------------------------------------
+ *        1       |      -      |  unchanged  |    unchanged     <- 모든 irq는 kernel이 제어.
+ *   -----------------------------------------------------------
+ *        0       |      1      |  non-secure |    non-secure    <- fiq는 모두 el3로.
+ *   -----------------------------------------------------------
+ *        0       |      0      |  unchanged  |    non-secure
+ *
+ *  여기서 비보안은 값이 1만큼 오른쪽으로 이동하고 MSB 비트가 설정되어 비보안 우선 순위
+ *  범위에 맞도록 하는 것을 의미합니다.
+ *
+ *  ICC_PMR_EL1과 인터럽트 우선 순위가 모두 수정되거나 변경되지 않은 처음 두 경우에는
+ *  동일한 우선 순위 집합을 사용할 수 있습니다. 
+ *
+ *  인터럽트 우선 순위만 비보안 범위로 수정되는 마지막 경우에는 다른 PMR 값을 사용하여
+ *  IRQ를 마스킹하고 나머지 값은 변경되지 않은 상태로 유지합니다.
+ *
+ *  - ICC_PMR_EL1 -> 
+ *
+ * - (gic_has_group0() && !gic_dist_security_disabled())
+ *   kernel이 group0 제어권이 있고. two security로 운영중이다.
+ *   kernel이 priorities에 대해서 반절만 제어를 하겠다는것.
+ *
+ *   group0     secure
+ *   true       single
+ *   true       two     <-- 이경우. two secure지만 fiq를 kernel이 제어할수있음.
+ *   false      two
+ *
+ *   (SCR_EL3.FIQ == 0 -> EL3가 fiq를 안받는다느것 -> kernel이 받는것 ->
+ *   group0는 kernel제어)
+ */
     if (gic_has_group0() && !gic_dist_security_disabled())
         static_branch_enable(&gic_nonsecure_priorities);
 
     static_branch_enable(&supports_pseudo_nmis);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - eoimode1동작이면 eoimo1에 IRQCHIP_SUPPORTS_NMI를 설정. 아닌 경우 eoimode0에 설정한다.
+ */
     if (static_branch_likely(&supports_deactivate_key))
         gic_eoimode1_chip.flags |= IRQCHIP_SUPPORTS_NMI;
     else
@@ -2353,7 +2509,7 @@ static void gic_enable_nmi_support(void)
 
 /*
  * IAMROOT, 2022.10.01:
- * - 
+ * - git init.
  */
 static int __init gic_init_bases(void __iomem *dist_base,
                  struct redist_region *rdist_regs,
@@ -2364,6 +2520,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
     u32 typer;
     int err;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - hyp가 아니면 딱히 eoimode1을 쓸필요없다. disable
+ */
     if (!is_hyp_mode_available())
         static_branch_disable(&supports_deactivate_key);
 
@@ -2444,6 +2604,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
     gic_smp_init();
     gic_cpu_pm_init();
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - SKIP
+ */
     if (gic_dist_supports_lpis()) {
         its_init(handle, &gic_data.rdists, gic_data.domain);
         its_cpu_init();
@@ -2452,6 +2616,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
             gicv2m_init(handle, gic_data.domain);
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - enable nmi
+ */
     gic_enable_nmi_support();
 
     return 0;
@@ -2478,6 +2646,21 @@ static int __init gic_validate_dist_version(void __iomem *dist_base)
 }
 
 /* Create all possible partitions at boot time */
+/*
+ * IAMROOT, 2022.10.29:
+ * - ex) dts
+ *
+ *   ppi-partitions {
+ *        ppi_cluster0: interrupt-partition-0 {
+ *            affinity = <&cpu_l0 &cpu_l1 &cpu_l2 &cpu_l3>;
+ *        };
+ *        ppi_cluster1: interrupt-partition-1 {
+ *            affinity = <&cpu_b0 &cpu_b1>;
+ *        };
+ *     };
+ *
+ *     이 예제로, nr_parts는 2개가 된다(ppi_cluster0, ppi_cluster1)
+ */
 static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
 {
     struct device_node *parts_node, *child_part;
@@ -2489,10 +2672,18 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
     if (!parts_node)
         return;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - ppi_nr은 이전에 이미 설정되었을것이다. 해당 값을 기준으로 만든다.
+ */
     gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
     if (!gic_data.ppi_descs)
         return;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - child node가 몇개 있는지
+ */
     nr_parts = of_get_child_count(parts_node);
 
     if (!nr_parts)
@@ -2513,6 +2704,12 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
         pr_info("GIC: PPI partition %pOFn[%d] { ",
             child_part, part_idx);
 
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - ex) affinity = <&cpu_l0 &cpu_l1 &cpu_l2 &cpu_l3>;
+ *   4개가 된다.
+ */
         n = of_property_count_elems_of_size(child_part, "affinity",
                             sizeof(u32));
         WARN_ON(n <= 0);
@@ -2522,6 +2719,26 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
             u32 cpu_phandle;
             struct device_node *cpu_node;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - ex) affinity = <&cpu_l0 &cpu_l1 &cpu_l2 &cpu_l3>;
+ *   에서 cpu_l0 의 예제
+ *   cpu_l0: cpu@0 {
+ *        device_type = "cpu";
+ *        compatible = "arm,cortex-a53";
+ *        reg = <0x0 0x0>;
+ *        enable-method = "psci";
+ *        capacity-dmips-mhz = <485>;
+ *        clocks = <&cru ARMCLKL>;
+ *        #cooling-cells = <2>; // min followed by max
+ *        dynamic-power-coefficient = <100>;
+ *        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+ *    };
+ *    이걸 cpu_node로 가져온다.(cpu_phandle은 cpu_l0에 대한 node및 arg값.)
+ *
+ *    affinity에서 index(cpu_l0, cpu_l1, ..)로 해당 cpu_phandle을 구해온다
+ *    -> 구해온 cpu_phandle로 실제 cpu_node(cpu_l0: cpu@0 {..})를 얻어온다.
+ */
             err = of_property_read_u32_index(child_part, "affinity",
                              i, &cpu_phandle);
             if (WARN_ON(err))
@@ -2531,6 +2748,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
             if (WARN_ON(!cpu_node))
                 continue;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - cpu번호를 구해온다. 구해오고 해당 cpu로 part->mask에 set한다.
+ */
             cpu = of_cpu_node_to_id(cpu_node);
             if (WARN_ON(cpu < 0))
                 continue;
diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index 8e76d2913e6b..33d65abaeeaf 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -132,6 +132,10 @@ static void partition_handle_irq(struct irq_desc *desc)
     chained_irq_exit(chip, desc);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 
+ */
 static int partition_domain_alloc(struct irq_domain *domain, unsigned int virq,
                   unsigned int nr_irqs, void *arg)
 {
@@ -142,6 +146,12 @@ static int partition_domain_alloc(struct irq_domain *domain, unsigned int virq,
     struct partition_desc *part;
 
     BUG_ON(nr_irqs != 1);
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic parition의 경우(partition_domain_ops)의 경우
+ *   translate = partition_domain_translate
+ */
     ret = domain->ops->translate(domain, fwspec, &hwirq, &type);
     if (ret)
         return ret;
@@ -171,6 +181,10 @@ static void partition_domain_free(struct irq_domain *domain, unsigned int virq,
     irq_domain_reset_irq_data(d);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @pariton_id와 일치하는 desc->parts의 index를 구해온다.
+ */
 int partition_translate_id(struct partition_desc *desc, void *partition_id)
 {
     struct partition_affinity *part = NULL;
@@ -191,6 +205,13 @@ int partition_translate_id(struct partition_desc *desc, void *partition_id)
     return i;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - partition_desc를 생성한다. 생성시 domain은 linear domain.
+ *   ops는 @ops를 따르되 free, alloc만 parition꺼로 고친다.
+ * - parition을 사용하는 interrupt에 한해 alloc과 free ops가 추가된다.
+ * 
+ */
 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
                          struct partition_affinity *parts,
                          int nr_parts,
@@ -232,6 +253,10 @@ struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
     return NULL;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @dsc의 domain을 가져온다. (partition domain)
+ */
 struct irq_domain *partition_get_domain(struct partition_desc *dsc)
 {
     if (dsc)
diff --git a/include/linux/cpu_pm.h b/include/linux/cpu_pm.h
index 552b8f9ea05e..fa8485162928 100644
--- a/include/linux/cpu_pm.h
+++ b/include/linux/cpu_pm.h
@@ -39,12 +39,20 @@
  */
 enum cpu_pm_event {
     /* A single cpu is entering a low power state */
+/*
+ * IAMROOT, 2022.10.29:
+ * - 절전 시작.
+ */
     CPU_PM_ENTER,
 
     /* A single cpu failed to enter a low power state */
     CPU_PM_ENTER_FAILED,
 
     /* A single cpu is exiting a low power state */
+/*
+ * IAMROOT, 2022.10.29:
+ * - 절전 해제
+ */
     CPU_PM_EXIT,
 
     /* A cpu power domain is entering a low power state */
diff --git a/include/linux/idr.h b/include/linux/idr.h
index a0dce14090a9..ea912d1a655e 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -16,6 +16,10 @@
 #include <linux/gfp.h>
 #include <linux/percpu.h>
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 정수기반의 radix tree.
+ */
 struct idr {
     struct radix_tree_root    idr_rt;
     unsigned int        idr_base;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index d6813947a0b9..02ad54c90805 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -68,6 +68,39 @@
  * IRQF_NO_DEBUG - Exclude from runnaway detection for IPI and similar handlers,
  *           depends on IRQF_PERCPU.
  */
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   이 플래그는 irq 처리 루틴의 일부로 커널에서만 사용됩니다.
+ *
+ *   IRQF_SHARED - 여러 장치 간에 irq를 공유할 수 있습니다.
+ *   IRQF_PROBE_SHARED - 공유 불일치가 발생할 것으로 예상할 때 호출자가 설정합니다.
+ *   IRQF_TIMER - 이 인터럽트를 타이머 인터럽트로 표시하는 플래그입니다.
+ *   IRQF_PERCPU - percpu interrupt.
+ *   IRQF_NOBALANCER - 이 인터럽트를 irq 밸런싱에서 제외하기 위한 플래그입니다. 
+ *   IRQF_IRQPOLL - 인터럽트가 폴링에 사용됩니다(성능상의 이유로 공유 인터럽트에
+ *                  먼저 등록된 인터럽트만 고려됨). 
+ *   IRQF_ONESHOT - hardirq 처리기가 완료된 후 인터럽트가 다시 활성화되지 않습니다. 
+ *     스레드 처리기가 실행될 때까지 irq 라인을 비활성화 상태로 유지해야 하는
+ *     스레드 인터럽트에서 사용됩니다.
+ *   IRQF_NO_SUSPEND - 일시 중단 중에 이 IRQ를 비활성화하지 마십시오. 이 인터럽트가
+ *     시스템을 일시 중단된 상태에서 깨우도록 보장하지 않습니다.
+ *     Documentation/power/suspend-and-interrupts.rst를 참조하십시오. 
+ *   IRQF_FORCE_RESUME - IRQF_NO_SUSPEND가 설정되어 있어도 다시 시작할 때 강제로
+ *     활성화합니다.
+ *   IRQF_NO_THREAD - 인터럽트를 스레드할 수 없습니다.
+ *   IRQF_EARLY_RESUME - 장치 재개 시간이 아닌 시스템 코어 중에 일찍 IRQ를 재개합니다.
+ *   IRQF_COND_SUSPEND - IRQ가 NO_SUSPEND 사용자와 공유되는 경우 인터럽트를 일시
+ *     중단한 후 이 인터럽트 핸들러를 실행합니다. 시스템 깨우기 장치의 경우
+ *     사용자는 인터럽트 처리기에서 깨우기 감지를 구현해야 합니다.
+ *   IRQF_NO_AUTOEN - 사용자가 요청할 때 IRQ 또는 NMI를 자동으로 활성화하지
+ *   마십시오.  사용자는 나중에 enable_irq() 또는 enable_nmi()를 통해 명시적으로
+ *   활성화합니다.
+ *   IRQF_NO_DEBUG - IRQF_PERCPU에 따라 IPI 및 유사한 처리기에 대한 런어웨이
+ *   감지에서 제외됩니다.
+.
+ */
 #define IRQF_SHARED        0x00000080
 #define IRQF_PROBE_SHARED    0x00000100
 #define __IRQF_TIMER        0x00000200
@@ -122,6 +155,11 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
  * @dir:    pointer to the proc/irq/NN/name entry
  */
 struct irqaction {
+/*
+ * IAMROOT, 2022.10.29:
+ * - primary hardirq handler
+ *   handler 호출 -- (return IRQ_WAKE_THREAD) -> thread_fn 호출 식의 흐름이 된다.
+ */
     irq_handler_t        handler;
     void            *dev_id;
     void __percpu        *percpu_dev_id;
diff --git a/include/linux/irqchip/irq-partition-percpu.h b/include/linux/irqchip/irq-partition-percpu.h
index 2f6ae7551748..da972f9285c1 100644
--- a/include/linux/irqchip/irq-partition-percpu.h
+++ b/include/linux/irqchip/irq-partition-percpu.h
@@ -13,6 +13,10 @@
 
 struct partition_affinity {
     cpumask_t            mask;
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic_populate_ppi_partitions()의 경우 fwnode가 들어간다.
+ */
     void                *partition_id;
 };
 
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index b9716dbf9c6a..b2c6391f5495 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -75,12 +75,28 @@ struct irq_desc {
     irq_flow_handler_t    handle_irq;
     struct irqaction    *action;    /* IRQ action list */
     unsigned int        status_use_accessors;
+/*
+ * IAMROOT, 2022.10.29:
+ * - istate define.
+ *   밖에서(driver) 건들지 말라는것.
+ */
     unsigned int        core_internal_state__do_not_mess_with_it;
+/*
+ * IAMROOT, 2022.10.29:
+ * - __enable_irq(), disable_irq()참고.
+ *   disable depth. 0인경우 암묵적으로 이미 enable인 상태라고 본다.
+ */
     unsigned int        depth;        /* nested irq disables */
     unsigned int        wake_depth;    /* nested wake enables */
     unsigned int        tot_count;
     unsigned int        irq_count;    /* For detecting broken IRQs */
     unsigned long        last_unhandled;    /* Aging timer for unhandled count */
+/*
+ * IAMROOT, 2022.10.29:
+ * - note_interrupt()에서 0.1초 이내에 여러번 irq가 IRQ_NONE일 경우 증가한다.
+ * - IRQ_NONE
+ *   정해진 handler가 호출이 안됫거나, dummy가 실행된경우등.
+ */
     unsigned int        irqs_unhandled;
     atomic_t        threads_handled;
     int            threads_handled_last;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 4901b4936ca0..52bfc1679525 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -453,6 +453,10 @@ extern unsigned int irq_create_mapping_affinity(struct irq_domain *host,
 extern unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec);
 extern void irq_dispose_mapping(unsigned int virq);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @hwirq의 virq를 @host에서 얻어온다. 없을경우 생성 및 mapping을 한다.
+ */
 static inline unsigned int irq_create_mapping(struct irq_domain *host,
                           irq_hw_number_t hwirq)
 {
@@ -474,6 +478,10 @@ static inline struct irq_desc *irq_resolve_mapping(struct irq_domain *domain,
  * @domain: domain owning this hardware interrupt
  * @hwirq: hardware irq number in that domain space
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - @hwirq로 virq를 domain에서 구해온다.
+ */
 static inline unsigned int irq_find_mapping(struct irq_domain *domain,
                         irq_hw_number_t hwirq)
 {
@@ -552,6 +560,16 @@ extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
 extern int irq_domain_activate_irq(struct irq_data *irq_data, bool early);
 extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 0번부터 scan하여 nr_irqs만큼 빈차리를 찾아 irq를 만든다.
+ *   @arg는 @domain->ops->alloc 실행히 마지막 인자로 private data로 들어간다.
+ * ex)
+ * gic_irq_domain_ops   : alloc = gic_irq_domain_alloc. arg = fwspec
+ * partition_domain_ops : default alloc = NULL.
+ *                        parition irq만(partition_create_desc())
+ *                        alloc = partition_domain_alloc
+ */
 static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
             unsigned int nr_irqs, int node, void *arg)
 {
@@ -587,6 +605,16 @@ extern void irq_domain_free_irqs_parent(struct irq_domain *domain,
 extern int irq_domain_disconnect_hierarchy(struct irq_domain *domain,
                        unsigned int virq);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irq_domain_check_hierarchy() 참고.
+ *   alloc ops가 있으면 domain 생성시 set해준다.
+ * ex)
+ * gic_irq_domain_ops   : alloc = gic_irq_domain_alloc. arg = fwspec
+ * partition_domain_ops : default alloc = NULL.
+ *                        parition irq만(partition_create_desc())
+ *                        alloc = partition_domain_alloc
+ */
 static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
 {
     return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index 246efc74e3f3..37dc903b984f 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -67,6 +67,10 @@ static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event ev
  *
  * This function has the same return conditions as raw_notifier_chain_register.
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - @nb(callback)등록.
+ */
 int cpu_pm_register_notifier(struct notifier_block *nb)
 {
     unsigned long flags;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index c7576c164db3..0e1f49b216b8 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -343,6 +343,10 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
     return ret;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - affinity managed가 설정이 되있다면 이미 activate했다고 가정하고 즉시 성공.
+ */
 int irq_activate(struct irq_desc *desc)
 {
     struct irq_data *d = irq_desc_get_irq_data(desc);
@@ -479,6 +483,12 @@ void irq_disable(struct irq_desc *desc)
     __irq_disable(desc, irq_settings_disable_unlazy(desc));
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irq_enable or irq_unmask 실행.
+ * - ex) giv3
+ *   irq_enable이 없다. gic_unmask_irq() 가 실행될것이다.
+ */
 void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
 {
     if (desc->irq_data.chip->irq_enable)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 0d894c6044bd..67cc3d5821a2 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -17,6 +17,10 @@
 # define IRQ_BITMAP_BITS    NR_IRQS
 #endif
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - struct irq_desc
+ */
 #define istate core_internal_state__do_not_mess_with_it
 
 extern bool noirqdebug;
@@ -321,6 +325,10 @@ static inline void irq_remove_timings(struct irq_desc *desc)
     irq_timings_free(irq_desc_get_irq(desc));
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irqt_stats에 irq번호로 자료구조를 하나 넣어놓는다.
+ */
 static inline void irq_setup_timings(struct irq_desc *desc, struct irqaction *act)
 {
     int irq = irq_desc_get_irq(desc);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 53462699c3b6..d1046f7eb624 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -461,6 +461,10 @@ EXPORT_SYMBOL_GPL(irq_domain_create_legacy);
  * @fwspec: FW specifier for an interrupt
  * @bus_token: domain-specific data
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - fwspec과 매칭되는 irq_domain을 irq_domain_list에서 찾는다.
+ */
 struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
                         enum irq_domain_bus_token bus_token)
 {
@@ -478,6 +482,13 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
      * selected.
      */
     mutex_lock(&irq_domain_mutex);
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - ex) gic_irq_domain_ops에서
+ *      select의 경우 : gic_irq_domain_select
+ * fwspec과 매칭되는 irq_domain을 irq_domain_list에서 찾는다.
+ */
     list_for_each_entry(h, &irq_domain_list, link) {
         if (h->ops->select && fwspec->param_count)
             rc = h->ops->select(h, fwspec, bus_token);
@@ -625,6 +636,11 @@ static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
     irq_domain_clear_mapping(domain, hwirq);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @virq에 @domain, hwirq를 mapping한다.
+ *   map ops가 있으면 실행을 해준다. @domain 자료구조에는 무조건  넣어준다.
+ */
 int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
              irq_hw_number_t hwirq)
 {
@@ -642,6 +658,10 @@ int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
     mutex_lock(&irq_domain_mutex);
     irq_data->hwirq = hwirq;
     irq_data->domain = domain;
+/*
+ * IAMROOT, 2022.10.29:
+ * - gic는 map ops가 없다.
+ */
     if (domain->ops->map) {
         ret = domain->ops->map(domain, virq, hwirq);
         if (ret != 0) {
@@ -745,6 +765,10 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
  * If the sense/trigger is to be specified, set_irq_type() should be called
  * on the number returned from that call.
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - @hwirq의 virq를 @domain에서 얻어온다. 없을경우 생성 및 mapping을 한다.
+ */
 unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
                        irq_hw_number_t hwirq,
                        const struct irq_affinity_desc *affinity)
@@ -766,6 +790,11 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
     of_node = irq_domain_get_of_node(domain);
 
     /* Check if mapping already exists */
+/*
+ * IAMROOT, 2022.10.29:
+ * - @domain에서 hwirq를 구해봐서 virq가 있으면 return. 없으면 생성후 @domain에
+ *   등록, mapping하여 return 한다.
+ */
     virq = irq_find_mapping(domain, hwirq);
     if (virq) {
         pr_debug("-> existing mapping on virq %d\n", virq);
@@ -823,6 +852,11 @@ static void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
         fwspec->param[i] = args[i];
 }
 
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - @fwspec의 hwirq로 virq를 등록 및 mapping한다.
+ */
 unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
 {
     struct irq_domain *domain;
@@ -832,6 +866,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
     int virq;
 
     if (fwspec->fwnode) {
+/*
+ * IAMROOT, 2022.10.29:
+ * - 처음에 가장 많이 쓰는 wired로 먼저 검색해보고 아니면 any로 검사한다.
+ */
         domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
         if (!domain)
             domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
@@ -845,6 +883,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
         return 0;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 찾아온 domain으로 hwirq, type을 구해온다.
+ */
     if (irq_domain_translate(domain, fwspec, &hwirq, &type))
         return 0;
 
@@ -852,6 +894,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
      * WARN if the irqchip returns a type with bits
      * outside the sense mask set and clear these bits.
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - IRQ_TYPE_SENSE_MASK외에 다른값들이 있으면 안된다. IRQ_TYPE_SENSE_MASK만 남긴다.
+ */
     if (WARN_ON(type & ~IRQ_TYPE_SENSE_MASK))
         type &= IRQ_TYPE_SENSE_MASK;
 
@@ -860,12 +906,21 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
      * don't do it again, or hell will break loose.
      */
     virq = irq_find_mapping(domain, hwirq);
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - hwirq에 해당하는 virq가 있으면 fwspec에서 정의된값과 일치한경우 즉시 return.
+ */
     if (virq) {
         /*
          * If the trigger type is not specified or matches the
          * current trigger type then we are done so return the
          * interrupt number.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - fwspec에 type 지정이 안됬거나, virq와 fwspec type과 동일한 경우 return..
+ */
         if (type == IRQ_TYPE_NONE || type == irq_get_trigger_type(virq))
             return virq;
 
@@ -873,6 +928,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
          * If the trigger type has not been set yet, then set
          * it now and return the interrupt number.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - virq에 아직 type설정이 안된경우 fwspec의 type으로 지정한다.
+ */
         if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) {
             irq_data = irq_get_irq_data(virq);
             if (!irq_data)
@@ -882,11 +941,24 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
             return virq;
         }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 이미 virq에 설정되있는데 fwspec과 일치하지 않는다. 바꾸진 않고 warn후 return err.
+ */
         pr_warn("type mismatch, failed to map hwirq-%lu for %s!\n",
             hwirq, of_node_full_name(to_of_node(fwspec->fwnode)));
         return 0;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 아직 hwirq에 대한 virq가 없는상태. virq를 구해와야된다.
+ */
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - @fwspec으로 @domain에 virq 1개를 아무노드에서 구해온다.
+ */
     if (irq_domain_is_hierarchy(domain)) {
         virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
         if (virq <= 0)
@@ -899,6 +971,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
     }
 
     irq_data = irq_get_irq_data(virq);
+/*
+ * IAMROOT, 2022.10.29:
+ * - error처리.
+ */
     if (!irq_data) {
         if (irq_domain_is_hierarchy(domain))
             irq_domain_free_irqs(virq, 1);
@@ -907,6 +983,10 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
         return 0;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @type을 irq_data에 설정한다.
+ */
     /* Store trigger type */
     irqd_set_trigger_type(irq_data, type);
 
@@ -958,6 +1038,10 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping);
  *
  * Returns the interrupt descriptor.
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - nomap, linear, tree인지에 따라 검색해온다.
+ */
 struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
                        irq_hw_number_t hwirq,
                        unsigned int *irq)
@@ -971,6 +1055,10 @@ struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
     if (domain == NULL)
         return desc;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - nomap
+ */
     if (irq_domain_is_nomap(domain)) {
         if (hwirq < domain->revmap_size) {
             data = irq_domain_get_irq_data(domain, hwirq);
@@ -981,6 +1069,10 @@ struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
         return desc;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - linear & tree
+ */
     rcu_read_lock();
     /* Check if the hwirq is in the linear revmap. */
     if (hwirq < domain->revmap_size)
@@ -1576,7 +1668,7 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain,
  * IAMROOT, 2022.10.15:
  * - @domain의 alloc ops를 호출해서 mapping한다.
  * - ex)
- *   gic_irq_domain_alloc
+ *   gic_irq_domain_alloc. arg는 fwspec.
  */
 int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain,
                     unsigned int irq_base,
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 3e858e86c873..a581ffcf7975 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -761,6 +761,10 @@ int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info)
 }
 EXPORT_SYMBOL_GPL(irq_set_vcpu_affinity);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - depth가 0일때만 disable.
+ */
 void __disable_irq(struct irq_desc *desc)
 {
     if (!desc->depth++)
@@ -856,6 +860,11 @@ void disable_nmi_nosync(unsigned int irq)
     disable_irq_nosync(irq);
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - depth가 1인 경우만 enable(irq_startup)을 한다.
+ *   irq_startup에서 depth는 0이 될것이다.
+ */
 void __enable_irq(struct irq_desc *desc)
 {
     switch (desc->depth) {
@@ -865,6 +874,10 @@ void __enable_irq(struct irq_desc *desc)
              irq_desc_get_irq(desc));
         break;
     case 1: {
+/*
+ * IAMROOT, 2022.10.29:
+ * - sleep상태라는것. enable 못한다.
+ */
         if (desc->istate & IRQS_SUSPENDED)
             goto err_out;
         /* Prevent probing on this irq: */
@@ -1681,7 +1694,52 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
  */
 /*
  * IAMROOT, 2022.10.15:
- * - 
+ * - 1. irq에 등록된 thread_fn에 대해 create. 및 wakeup
+ *   2. old action이 있는지 판단하여 shared irq인지 결정.
+ *   3. shared 인지 아닌지 에 따라 flag검사 및, flag를  보며 irq_activate, enable_irq 결정
+ *   4. thread_mask set 처리.
+ *   5. onshot 관련 flag 처리.
+ *   6. irqt_stat에 생성된 irq번호로 자료구조 추가.
+ *   7. /proc/에 생성된 irq번호로 자료구조 추가.
+ *
+ * - irq 흐름.
+ *   vector
+ *     v
+ *   chip handler
+ *     v
+ *   flow handler
+ *     v
+ *   irq_handler(현재)
+ *
+ * - new->thread_fn이 존재하고 nested가 안됬다면
+ *   setup_irq_thread()에서 irq_thread를 생성하여 new->thread에 넣어놓고,
+ *   __setup_irq 마무리 시점에서 wakeup 시켜놓는다.
+ *   wakeup된 irq_thread()는 irq_wait_for_interrupt로 기다리면서 
+ *   thread_fn을 실행한다.
+ *
+ *  ====== __setup_irq =====
+ *   thread_fn()존재, !nested
+ *          |
+ *          v
+ *    new->thread = irq_thread
+ *          |
+ *          v
+ *    irq_thread() wakeup
+ *  ======================
+ *
+ *  ====== irq_thread() ======
+ *   threa_fn()이 있는경우 __setup_irq에서 create된후 wakeup됨.
+ *            |
+ *            v
+ *        irq_wait_for_interrupt()대기 <---------------------------------------+
+ *            |                                                                |
+*             (interrupt발생 후 handler 호출후 return IRQ_WAKE_THREAD)         |
+ *            |                                                                |
+ *            v                                                                |
+ *        thread_fn()실행 -----------------------------------------------------+
+ * ==========================
+ *
+ *
  */
 static int
 __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
@@ -1909,6 +1967,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
             irqd_set_trigger_type(&desc->irq_data, oldtype);
         }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 다음 상황이면 mismatch
+ * 1. !((old->flags & new->flags) & IRQF_SHARED)
+ *    old, new 하나라도 shared가 없는 상황..
+ * 2. (oldtype != (new->flags & IRQF_TRIGGER_MASK))
+ *  서로 타입이 다른 경우.
+ * 3. ((old->flags ^ new->flags) & IRQF_ONESHOT))
+ *   둘중 하나만 oneshot이 있는 경우.
+ * 4. (old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU)
+ *   percpu flag가 다른경우.
+ */
         if (!((old->flags & new->flags) & IRQF_SHARED) ||
             (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||
             ((old->flags ^ new->flags) & IRQF_ONESHOT))
@@ -1919,6 +1989,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
             (new->flags & IRQF_PERCPU))
             goto mismatch;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - old를 전부 iter하면서 thread_mask에 old의 thread_mask를 전부 or해준다.
+ */
         /* add new interrupt at end of irq queue */
         do {
             /*
@@ -1938,11 +2012,24 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
      * !ONESHOT irqs the thread mask is 0 so we can avoid a
      * conditional in irq_wake_thread().
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   ONESHOT에 대한 이 irqaction에 대한 스레드 마스크를 설정합니다.
+ *   !ONESHOT irqs의 경우 스레드 마스크는 0이므로 irq_wake_thread()에서 조건부를
+ *   피할 수 있습니다.
+ */
     if (new->flags & IRQF_ONESHOT) {
         /*
          * Unlikely to have 32 resp 64 irqs sharing one line,
          * but who knows.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   한 줄을 공유하는 32개의 resp 64 irq를 가질 가능성은 없지만 누가 알겠습니까.
+ * - 한개의 interrupt line에 대해서 너무 많이 공유를 하고 있는 경우.
+ */
         if (thread_mask == ~0UL) {
             ret = -EBUSY;
             goto out_unlock;
@@ -1967,6 +2054,26 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
          * thread_mask assigned. See the loop above which or's
          * all existing action->thread_mask bits.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   작업에 대한 thread_mask는 IRQF_ONESHOT 스레드 핸들러가 깨웠지만 아직 완료되지
+ *   않았음을 나타내기 위해 desc->thread_active로 지정됩니다. 스레드가 완료되면
+ *   비트가 지워집니다. 공유 인터럽트 라인의 모든 스레드가 완료되면
+ *   desc->threads_active는 0이 되고 인터럽트 라인은 마스크 해제됩니다.
+ *   handle.c 참조: 자세한 내용은 irq_wake_thread()를 참조하십시오. 
+ *
+ *   기본(하드 irq 컨텍스트) 인터럽트 핸들러에 의해 깨어난 스레드가 없으면 영향을
+ *   받는 하드 irq 흐름 핸들러(handle_[fasteoi|level]_irq)에서 irq 라인의 마스크를
+ *   해제하기 위해 desc->threads_active도 0으로 확인됩니다. 
+ *
+ *   새 작업은 할당된 thread_mask의 첫 번째 0비트를 가져옵니다. 위의 모든 기존
+ *   action->thread_mask 비트가 있는 루프를 참조하십시오.
+ *
+ * - 비어있는 threadmask bit를 가져오고 thread가 완료되기 전까지 해당 bit를 set
+ *   할 것이다.
+ * - thread가 완료되면 해당 bit는 unset이 될것이다.(irq_wake_thread()참조)
+ */
         new->thread_mask = 1UL << ffz(thread_mask);
 
     } else if (new->handler == irq_default_primary_handler &&
@@ -1986,17 +2093,47 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
          * has. The type flags are unreliable as the
          * underlying chip implementation can override them.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   핸들러 = NULL로 인터럽트가 요청되었으므로 기본 기본 핸들러를 사용합니다.
+ *   그러나 oneshot 플래그가 설정되어 있지 않습니다. 레벨 인터럽트와 함께 이것은
+ *   치명적입니다. 기본 기본 핸들러가 스레드를 깨우기만 하면 irq 라인이 다시
+ *   활성화되지만 장치에는 여전히 irq 레벨이 지정되어 있기 때문입니다. 헹구고
+ *   반복...
+ *   이것은 에지 유형 인터럽트에 대해 작동하지만 이 인터럽트가 실제로 어떤
+ *   유형인지 말할 수 없기 때문에 안전하게 처리하고 무조건 거부합니다. 기본 칩
+ *   구현에서 유형 플래그를 재정의할 수 있으므로 유형 플래그를 신뢰할 수 없습니다. 
+ *
+ * - handler 지정이 안된 상황에서 , oneshot이 아닐경우 해당 irq가 계속 들어와 default
+ *   handler를 계속 호출할 것이다. 의미 없는 행동이므로 error.
+ * - edge trigger일 경우 interrupt가 한번 들어올때마다 한번씩 호출 될것이지만
+ *   level trigeer일 경우 level이 끝날때까지 계속 여러번 호출될 위험이 있다.
+ */
         pr_err("Threaded irq requested with handler=NULL and !ONESHOT for %s (irq %d)\n",
                new->name, irq);
         ret = -EINVAL;
         goto out_unlock;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - old가 이미 있는 상황(irqaction이 2개이상)인지 검사한다.
+ */
     if (!shared) {
+/*
+ * IAMROOT, 2022.10.29:
+ * - shared가 아닌 경우.
+ */
         init_waitqueue_head(&desc->wait_for_threads);
 
         /* Setup the type (level, edge polarity) if configured: */
         if (new->flags & IRQF_TRIGGER_MASK) {
+
+/*
+ * IAMROOT, 2022.10.29:
+ * - 요청 trigger로 irq를 변경해준다.
+ */
             ret = __irq_set_trigger(desc,
                         new->flags & IRQF_TRIGGER_MASK);
 
@@ -2015,6 +2152,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
          * fails. Interrupts which are in managed shutdown mode
          * will simply ignore that activation request.
          */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   인터럽트를 활성화합니다. 해당 활성화는 IRQ_NOAUTOEN과 독립적으로 발생해야
+ *   합니다. request_irq()는 실패할 수 있으며 호출자는 이를 처리해야 합니다.
+ *   IRQ_NOAUTOEN으로 요청된 인터럽트의 enable_irq()는 실패하지 않아야 합니다.
+ *   활성화는 시스템을 종료 모드로 유지하고 필요한 경우 리소스를 연결하고 이것이
+ *   가능하지 않은 경우 실패합니다. 관리 종료 모드에 있는 인터럽트는 해당 활성화
+ *   요청을 무시합니다.
+ */
         ret = irq_activate(desc);
         if (ret)
             goto out_unlock;
@@ -2030,6 +2177,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 irq_settings_set_no_debug(desc);
         }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - kernel/irq/spurious.c
+ */
         if (noirqdebug)
             irq_settings_set_no_debug(desc);
 
@@ -2042,6 +2193,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
             irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
         }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - auto enable 한다.
+ *   irq_startup을 하면서 desc->depth = 0이 된다.
+ */
         if (!(new->flags & IRQF_NO_AUTOEN) &&
             irq_settings_can_autoenable(desc)) {
             irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
@@ -2052,6 +2208,20 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
              * it while it's still disabled and then wait for
              * interrupts forever.
              */
+/*
+ * IAMROOT, 2022.10.29:
+ * - papago
+ *   공유 인터럽트는 자동 활성화를 비활성화하는 데 적합하지 않습니다. 공유
+ *   인터럽트는 여전히 비활성화되어 있는 동안 요청한 다음 인터럽트를 영원히 기다릴
+ *   수 있습니다.
+ *
+ * - no auto enable.
+ *   shared interrupt는 따로 enable하기가 까다로울있어서 영원히 enable안될수있다.
+ *
+ * - desc->depth = 1
+ *   disable 상태에서 출발을 한다는 의미. __enalbe_irq시 depth == 1인 경우
+ *   irq_startup을 하면서 depth = 0이 될것이다.
+ */
             WARN_ON_ONCE(new->flags & IRQF_SHARED);
             /* Undo nested disables: */
             desc->depth = 1;
@@ -2061,6 +2231,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
         unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - shared인 상황에서, 현재 shared중인 irq와, 요청 trigger가 다른경우 shared
+ *   인것을 바꾸는건 안되므로 경고출력.
+ */
         if (nmsk != omsk)
             /* hope the handler works with current  trigger mode */
             pr_warn("irq %d uses trigger mode %u; requested %u\n",
@@ -2079,6 +2254,14 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
      * Check whether we disabled the irq via the spurious handler
      * before. Reenable it and give it another chance.
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - shared irq이면서, spurious를 허용을 안한경우. 이 시점에서 enable을 한다.
+ *   shared는 spurious disable를 용납안한다.
+ *   A, B, C driver가 irq를 shared한다고 할때, A, B가 동작중이고, C가 새로 등록되기전에
+ *   C interrupt가 들어올수가 있어 spurious가 될수밖에 없다. 이러한 상황때문에
+ *   spurious를 반드시 해야되므로 spurious disable은 불가능하다.
+ */
     if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
         desc->istate &= ~IRQS_SPURIOUS_DISABLED;
         __enable_irq(desc);
@@ -2088,12 +2271,20 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
     chip_bus_sync_unlock(desc);
     mutex_unlock(&desc->request_mutex);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irqt_stat에 new에 대한 자료구조를 생성한다.
+ */
     irq_setup_timings(desc, new);
 
     /*
      * Strictly no need to wake it up, but hung_task complains
      * when no hard interrupt wakes the thread up.
      */
+/*
+ * IAMROOT, 2022.10.29:
+ * - new->thread, new->secondary를 실행한다.
+ */
     if (new->thread)
         wake_up_process(new->thread);
     if (new->secondary)
@@ -2647,6 +2838,10 @@ int request_nmi(unsigned int irq, irq_handler_t handler,
     return retval;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @type에 따라 trigger 설정후 current cpu에 대한 enable irq수행.
+ */
 void enable_percpu_irq(unsigned int irq, unsigned int type)
 {
     unsigned int cpu = smp_processor_id();
@@ -2661,6 +2856,10 @@ void enable_percpu_irq(unsigned int irq, unsigned int type)
      * use the default for this interrupt.
      */
     type &= IRQ_TYPE_SENSE_MASK;
+/*
+ * IAMROOT, 2022.10.29:
+ * - @type 요청이 없으면 desc에서 type을 가져와서 설정한다.
+ */
     if (type == IRQ_TYPE_NONE)
         type = irqd_get_trigger_type(&desc->irq_data);
 
@@ -2886,8 +3085,13 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)
  * - ex) ipi의 경우 ipi_handler()
  *
  * - irq 흐름.
- *   vector -> chip handler -> flow handler -> irq_handler(현재) ->
- *   action handler(option)
+ *   vector
+ *     v
+ *   chip handler
+ *     v
+ *   flow handler
+ *     v
+ *   irq_handler(현재)
  */
 int __request_percpu_irq(unsigned int irq, irq_handler_t handler,
              unsigned long flags, const char *devname,
@@ -2944,8 +3148,16 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler,
         return retval;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irq에 대한 setup.
+ */
     retval = __setup_irq(irq, desc, action);
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - error 처리.,
+ */
     if (retval) {
         irq_chip_pm_put(&desc->irq_data);
         kfree(action);
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index ca71123a6130..d7163b503b0b 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -30,6 +30,10 @@ bool irq_pm_check_wakeup(struct irq_desc *desc)
  * Called from __setup_irq() with desc->lock held after @action has
  * been installed in the action chain.
  */
+/*
+ * IAMROOT, 2022.10.29:
+ * - pm에 action을 추가한다.
+ */
 void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action)
 {
     desc->nr_actions++;
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index ee595ec09778..b68e81141833 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -316,6 +316,10 @@ static int name_unique(unsigned int irq, struct irqaction *new_action)
     return ret;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - /proc/irq/(번호)/handler/ 를 만든다.
+ */
 void register_handler_proc(unsigned int irq, struct irqaction *action)
 {
     char name [MAX_NAMELEN];
@@ -335,6 +339,10 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
 
 #define MAX_NAMELEN 10
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - @irq로 /proc/irq에 만든다.
+ */
 void register_irq_proc(unsigned int irq, struct irq_desc *desc)
 {
     static DEFINE_MUTEX(register_lock);
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index c481d8458325..41d3e212368a 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -382,6 +382,11 @@ void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret)
         }
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - 실패된 경우, irqs_unhandled를 1로 reset할지 증가할지를 판단한다.
+ *   마지막 실패이후 0.1초 이상 지낫으면 reset. 아니면 증가.
+ */
     if (unlikely(action_ret == IRQ_NONE)) {
         /*
          * If we are seeing only the odd spurious IRQ caused by
@@ -431,6 +436,11 @@ void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret)
     desc->irqs_unhandled = 0;
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - __setup_irq()함수등에서 irq_settings_set_no_debug()를 호출하게 한다. 
+ *   _IRQ_NO_DEBUG set용도.
+ */
 bool noirqdebug __read_mostly;
 
 int noirqdebug_setup(char *str)
diff --git a/kernel/irq/timings.c b/kernel/irq/timings.c
index c43e2ac2f8de..6fad89944616 100644
--- a/kernel/irq/timings.c
+++ b/kernel/irq/timings.c
@@ -602,6 +602,10 @@ void irq_timings_free(int irq)
     }
 }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irqt_stats에 없으면 memory 할당후 irqt_stats에 넣는다.
+ */
 int irq_timings_alloc(int irq)
 {
     struct irqt_stat __percpu *s;
@@ -777,12 +781,20 @@ static int __init irq_timings_test_irqs(struct timings_intervals *ti)
     struct irqt_stat *irqs;
     int i, index, ret, irq = 0xACE5;
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irqt_stats에 있으면 아무것도 안하고, 없으면 alloc.
+ */
     ret = irq_timings_alloc(irq);
     if (ret) {
         pr_err("Failed to allocate irq timings\n");
         return ret;
     }
 
+/*
+ * IAMROOT, 2022.10.29:
+ * - irq를 irqt_stats에서 찾는다 없으면 error.
+ */
     s = idr_find(&irqt_stats, irq);
     if (!s) {
         ret = -EIDRM;
 

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 623
165 [커널 19차] 27 주차 Min 2022.11.22 82
164 [커널 18차] 78주차 kkr 2022.11.19 186
163 [커널 19차] 25 ~ 26 주차 Min 2022.11.14 71
162 [커널 18차] 76-77주차 kkr 2022.11.12 384
161 [커널 19차] 24주차 Min 2022.10.31 108
160 [커널 17차] 112주차 ㅇㅇㅇ 2022.10.30 81
» [커널 18차] 75주차 kkr 2022.10.29 40
158 [커널 17차] 107 ~ 111주차 ㅇㅇㅇ 2022.10.23 71
157 [커널 19차] 22주차 Min 2022.10.17 76
156 [커널 18차] 73주차 kkr 2022.10.15 44
155 [커널 18차] 72주차 kkr 2022.10.09 182
154 [커널 18차] 71주차 kkr 2022.10.01 74
153 [커널 18차] 70주차 kkr 2022.09.24 76
152 [커널 18차] 69주차 kkr 2022.09.22 57
151 [커널 17차] 105~106주차 ㅇㅇㅇ 2022.09.18 50
150 [커널 17차] 104주차 ㅇㅇㅇ 2022.09.04 87
149 [커널 18차] 67주차 kkr 2022.09.03 137
148 [커널 17차] 103주차 ㅇㅇㅇ 2022.08.28 35
147 [커널 18차] 66주차 kkr 2022.08.27 74
146 [커널 17차] 101~102주차 ㅇㅇㅇ 2022.08.21 45
XE Login