[커널 18차] 75주차
2022.10.29 22:18
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;
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | 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 |
.