中断分析1

    xiaoxiao2022-07-04  125

    1. __gic_init_bases

    1043 static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, 1044 void __iomem *dist_base, void __iomem *cpu_base, 1045 u32 percpu_offset, struct fwnode_handle *handle) 1046 { 1047 irq_hw_number_t hwirq_base; 1048 struct gic_chip_data *gic; 1049 int gic_irqs, irq_base, i; 1050 1051 BUG_ON(gic_nr >= MAX_GIC_NR); 1052 1053 gic_check_cpu_features(); 1054 1055 gic = &gic_data[gic_nr]; 1056 #ifdef CONFIG_GIC_NON_BANKED 1057 if (percpu_offset) { /* Frankein-GIC without banked registers... */ 1058 unsigned int cpu; 1059 1060 gic->dist_base.percpu_base = alloc_percpu(void __iomem *); 1061 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *); 1062 if (WARN_ON(!gic->dist_base.percpu_base || 1063 !gic->cpu_base.percpu_base)) { 1064 free_percpu(gic->dist_base.percpu_base); 1065 free_percpu(gic->cpu_base.percpu_base); 1066 return; 1067 } 1068 1069 for_each_possible_cpu(cpu) { 1070 u32 mpidr = cpu_logical_map(cpu); 1071 u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); 1072 unsigned long offset = percpu_offset * core_id; 1073 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset; 1074 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset; 1075 } 1076 1077 gic_set_base_accessor(gic, gic_get_percpu_base); 1078 } else 1079 #endif 1080 { /* Normal, sane GIC... */ 1081 WARN(percpu_offset, 1082 "GIC_NON_BANKED not enabled, ignoring x offset!", 1083 percpu_offset); 1084 gic->dist_base.common_base = dist_base; 1085 gic->cpu_base.common_base = cpu_base; 1086 gic_set_base_accessor(gic, gic_get_common_base); 1087 } 1088 1089 /* 1090 * Find out how many interrupts are supported. 1091 * The GIC only supports up to 1020 interrupt sources. 1092 */ 1093 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f; 1094 gic_irqs = (gic_irqs + 1) * 32; 1095 printk("tom gic_irqs=%x\n",gic_irqs); 1096 if (gic_irqs > 1020) 1097 gic_irqs = 1020; 1098 gic->gic_irqs = gic_irqs; 1099 1100 if (handle) { /* DT/ACPI */ 1101 printk(KERN_ERR "tom before irq_domain_create_linear\n"); 1102 gic->domain = irq_domain_create_linear(handle, gic_irqs, 1103 &gic_irq_domain_hierarchy_ops, 1104 gic); 1105 } else { /* Legacy support */ 1106 /* 1107 * For primary GICs, skip over SGIs. 1108 * For secondary GICs, skip over PPIs, too. 1109 */ 1110 if (gic_nr == 0 && (irq_start & 31) > 0) { 1111 hwirq_base = 16; 1112 if (irq_start != -1) 1113 irq_start = (irq_start & ~31) + 16; 1114 } else { 1115 hwirq_base = 32; 1116 } 1117 1118 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ 1119 1120 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, 1121 numa_node_id()); 1122 if (IS_ERR_VALUE(irq_base)) { 1123 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 1124 irq_start); 1125 irq_base = irq_start; 1126 } 1128 gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, 1129 hwirq_base, &gic_irq_domain_ops, gic); 1130 } 1131 1132 if (WARN_ON(!gic->domain)) 1133 return; 1134 1135 if (gic_nr == 0) { 1136 /* 1137 * Initialize the CPU interface map to all CPUs. 1138 * It will be refined as each CPU probes its ID. 1139 * This is only necessary for the primary GIC. 1140 */ 1141 for (i = 0; i < NR_GIC_CPU_IF; i++) 1142 gic_cpu_map[i] = 0xff; 1143 #ifdef CONFIG_SMP 1144 set_smp_cross_call(gic_raise_softirq); 1145 register_cpu_notifier(&gic_cpu_notifier); 1146 #endif 1147 set_handle_irq(gic_handle_irq); 1148 if (static_key_true(&supports_deactivate)) 1149 pr_info("GIC: Using split EOI/Deactivate mode\n"); 1150 } 1151 1152 gic_dist_init(gic); 1153 gic_cpu_init(gic); 1154 gic_pm_init(gic); 1155 }

    函数流程:

    把中断控制器和CPU的地址给gic在1102行中,调用函数 gic->domain = irq_domain_create_linear(handle, gic_irqs, &gic_irq_domain_hierarchy_ops, gic); 参数: gic_irqs= 0x60 handle- >type=FWNODE_OF=1 handle->secondary=NULL 后续可以通过to_of_node找到这个node节点,通过 irq_domain_create_linear创建一个domain。

    2. 初始化gic的dist

    135 #define gic_data_dist_base(d) ((d)->dist_base.common_base) 136 #define gic_data_cpu_base(d) ((d)->cpu_base.common_base) 72 static void __init gic_dist_init(struct gic_chip_data *gic) 473 { 474 unsigned int i; 475 u32 cpumask; 476 unsigned int gic_irqs = gic->gic_irqs; 477 void __iomem *base = gic_data_dist_base(gic); 478 479 writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL); 480 481 /* 482 * Set all global interrupts to this CPU only. 483 */ 484 cpumask = gic_get_cpumask(gic); 485 cpumask |= cpumask << 8; 486 cpumask |= cpumask << 16; 487 for (i = 32; i < gic_irqs; i += 4) 488 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); 489 490 gic_dist_config(base, gic_irqs, NULL); 491 492 writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL); 493 }

    说明: 1)在477行得到的是dts gic的reg的第1个地址的虚拟地址

    下面是创建是domain,并且加入链表irq_domain_list中。

    3. irq_domain_create_linear

    261 static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, 262 unsigned int size, 263 const struct irq_domain_ops *ops, 264 void *host_data) 265 { 266 return __irq_domain_add(fwnode, size, size, 0, ops, host_data); 267 }

    参数: fwnode:就是gic node的handle size: 就是gic支持irq数量 ops: irq_domain_ops操作 host_data: 就是gic的数据,

    例如: gic->dist_base.common_base(gic的dist address) gic->cpu_base.common_base (gic的 cpu register)

    4. __irq_domain_add

    函数的作用: 1)分配一个irq_domain数据结构 2)初始化这个domain的数据, ops(函数操作), host_data, 3) list_add(&domain->link, &irq_domain_list)把这个domain加入到irq_domain_list链表。

    of_node:就是对应着interrupt controller内容,是通过to_of_node从fwnode得到of_node。

    94 struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, 95 irq_hw_number_t hwirq_max, int direct_max, 96 const struct irq_domain_ops *ops, 97 void *host_data) 98 { 99 struct irq_domain *domain; 100 struct device_node *of_node; 101 102 of_node = to_of_node(fwnode); 103 104 domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), 105 GFP_KERNEL, of_node_to_nid(of_node)); 106 if (WARN_ON(!domain)) 107 return NULL; 108 109 of_node_get(of_node); 110 111 /* Fill structure */ 112 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); 113 domain->ops = ops; 114 domain->host_data = host_data; 115 domain->fwnode = fwnode; 116 domain->hwirq_max = hwirq_max; 117 domain->revmap_size = size; 118 domain->revmap_direct_max_irq = direct_max; 119 irq_domain_check_hierarchy(domain); 120 121 mutex_lock(&irq_domain_mutex); 122 list_add(&domain->link, &irq_domain_list); 123 mutex_unlock(&irq_domain_mutex); 124 125 pr_debug("Added domain %s\n", domain->name); 126 return domain; 127 }

    5. 解析dts中中断,并更新索引。

    现在从uart例子分析,dts的配置如下

    157 v2m_serial0: uart@09000 { 158 compatible = "arm,pl011", "arm,primecell"; 159 reg = <0x09000 0x1000>; 160 interrupts = <5>; 161 clocks = <&v2m_oscclk2>, <&smbclk>; 162 clock-names = "uartclk", "apb_pclk"; 163 }; 164 165 v2m_serial1: uart@0a000 { 166 compatible = "arm,pl011", "arm,primecell"; 167 reg = <0x0a000 0x1000>; 168 interrupts = <6>; 169 clocks = <&v2m_oscclk2>, <&smbclk>; 170 clock-names = "uartclk", "apb_pclk"; 171 }; 172 173 v2m_serial2: uart@0b000 { 174 compatible = "arm,pl011", "arm,primecell"; 175 reg = <0x0b000 0x1000>; 176 interrupts = <7>; 177 clocks = <&v2m_oscclk2>, <&smbclk>; 178 clock-names = "uartclk", "apb_pclk"; 179 }; 180 181 v2m_serial3: uart@0c000 { 182 compatible = "arm,pl011", "arm,primecell"; 183 reg = <0x0c000 0x1000>; 184 interrupts = <8>; 185 clocks = <&v2m_oscclk2>, <&smbclk>; 186 clock-names = "uartclk", "apb_pclk"; 187 };

    调用流程: of_platform_bus_create----->of_platform_device_create_pdata—>irq_of_parse_and_map

    5.1 irq_of_parse_and_map

    38 unsigned int irq_of_parse_and_map(struct device_node *dev, int index) 39 { 40 struct of_phandle_args oirq; 41 printk(KERN_ERR "tom irq_of_parse_and_map name=%s",dev->name); 42 43 if (of_irq_parse_one(dev, index, &oirq)) 44 return 0; 45 46 return irq_create_of_mapping(&oirq); 47 }
    最新回复(0)