内核版本
内核版本: 4.4.174
irq_create_fwspec_mapping
在irq_create_fwspec_mapping函数中调用irq_domain_alloc_irqs函数:
fwspec->param[0]=0 fwspec->param[1]=7 fwspec->param[2]=4
//fwspec->param[0]=0 fwspec->param[1]=7 fwspec->param[2]=4
//fwspec->param_count=3
//to_of_node(fwspec->fwnode)=/interrupt-controller@1e001000
//domain->name=GIC NUMA_NO_NODE=-1
virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
irq_domain_alloc_irqs
//domain->name=GIC nr_irqs=1 node=-1
364 static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
365 unsigned int nr_irqs, int node, void *arg)
366 {
367 return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
368 }
__irq_domain_alloc_irqs
步骤:
1)irq_domain_alloc_descs:分配irq和对应的desc,并把virq和desc加入到irq_desc_tree的radix树
2)irq_domain_insert_irq: 保存hwirq和virq的映射表
3)irq_domain_alloc_irqs_recursive去调用ret = domain->ops->alloc(domain, //irq_base, nr_irqs, arg);然后call到该层中断控制器的domain的ops的alloc函数。(回头去研究下)
1148 /**
1149 * __irq_domain_alloc_irqs - Allocate IRQs from domain
1150 * @domain: domain to allocate from
1151 * @irq_base: allocate specified IRQ nubmer if irq_base >= 0
1152 * @nr_irqs: number of IRQs to allocate
1153 * @node: NUMA node id for memory allocation
1154 * @arg: domain specific argument
1155 * @realloc: IRQ descriptors have already been allocated if true
1156 *
1157 * Allocate IRQ numbers and initialized all data structures to support
1158 * hierarchy IRQ domains.
1159 * Parameter @realloc is mainly to support legacy IRQs.
1160 * Returns error code or allocated IRQ number
1161 *
1162 * The whole process to setup an IRQ has been split into two steps.
1163 * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
1164 * descriptor and required hardware resources. The second step,
1165 * irq_domain_activate_irq(), is to program hardwares with preallocated
1166 * resources. In this way, it's easier to rollback when failing to
1167 * allocate resources.
1168 */
1169 int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
1170 unsigned int nr_irqs, int node, void *arg,
1171 bool realloc)
1172 {
1173 int i, ret, virq;
1174
1175 if (domain == NULL) {
1176 domain = irq_default_domain;
1177 if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
1178 return -EINVAL;
1179 }
1180
1181 if (!domain->ops->alloc) {
1182 pr_debug("domain->ops->alloc() is NULL\n");
1183 return -ENOSYS;
1184 }
1185
1186 if (realloc && irq_base >= 0) {
1187 virq = irq_base;
1188 } else {
//irq_base=0 nr_irqs=1 node=-1
1189 virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
//分配virq以及对应的desc,并把virq和desc加入到irq_desc_tree的radix树
1190 if (virq < 0) {
1191 pr_debug("cannot allocate IRQ(base %d, count %d)\n",
1192 irq_base, nr_irqs);
1193 return virq;
1194 }
1195 }
1196
1197 if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
1198 pr_debug("cannot allocate memory for IRQ%d\n", virq);
1199 ret = -ENOMEM;
1200 goto out_free_desc;
1201 }
1202
1203 mutex_lock(&irq_domain_mutex);
1204 ret = irq_domain_alloc_irqs_recursive(domain, virq, nr_irqs, arg);
// desc->handle_irq:这个函数用来触发和virq绑定的中断处理事件,这个函数一定要用本级实现的函数去重新赋值,否则是空的
//desc->handle_irq的初始话,在建立映射表的时候通过irq_domain_alloc_irqs_recursive去调用ret = domain->ops->alloc(domain, //irq_base, nr_irqs, arg);然后call到该层中断控制器的domain的ops的alloc函数。
1205 if (ret < 0) {
1206 mutex_unlock(&irq_domain_mutex);
1207 goto out_free_irq_data;
1208 }
1209 for (i = 0; i < nr_irqs; i++)
1210 irq_domain_insert_irq(virq + i);
// irq_domain_insert_virq保存hwirq和virq映射表
//892 static void irq_domain_insert_irq(int virq)
// 893 {
//894 struct irq_data *data;
//895
//896 for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
// 897 struct irq_domain *domain = data->domain;
//898 irq_hw_number_t hwirq = data->hwirq;
//899
//domain->revmap_size=0x60=96
//当hwirq小于domain->revmap_size,使用domain->linear_revmap保存hwirq和virq的映射关系
//当hwirq大于domain->revmap_size,使用domain->revmap_tree保存hwirq和irq_data。
//这样hwirq和irq_data->irq形成了映射保存在domain->revmap_tree树中。
//900 if (hwirq < domain->revmap_size) {
//901 domain->linear_revmap[hwirq] = virq;
//902 } else {
//903 mutex_lock(&revmap_trees_mutex);
//904 radix_tree_insert(&domain->revmap_tree, hwirq, data);
//905 mutex_unlock(&revmap_trees_mutex);
//906 }
//907
//908 /* If not already assigned, give the domain the chip's name */
//909 if (!domain->name && data->chip)
//910 domain->name = data->chip->name;
//911 }
//912
//913 irq_clear_status_flags(virq, IRQ_NOREQUEST);
//914 }
1211 mutex_unlock(&irq_domain_mutex);
1212
1213 return virq;
1214
1215 out_free_irq_data:
1216 irq_domain_free_irq_data(virq, nr_irqs);
1217 out_free_desc:
1218 irq_free_descs(virq, nr_irqs);
1219 return ret;
1220 }
irq_domain_alloc_descs
836 static int irq_domain_alloc_descs(int virq, unsigned int cnt,
837 irq_hw_number_t hwirq, int node)
838 {
839 unsigned int hint;
840
// virq = -1 cnt=1 hwirq=0 node=-1
841 if (virq >= 0) {
842 virq = irq_alloc_descs(virq, virq, cnt, node);
843 } else {
844 hint = hwirq % nr_irqs;
845 if (hint == 0)
846 hint++;
//hint = 1, cnt = 1, node = -1
847 virq = irq_alloc_descs_from(hint, cnt, node);
848 if (virq <= 0 && hint > 1)
849 virq = irq_alloc_descs_from(1, cnt, node);
850 }
851
852 return virq;
853 }
irq_alloc_descs_from
702 #define irq_alloc_descs_from(from, cnt, node) \
703 irq_alloc_descs(-1, from, cnt, node)
// irq_alloc_descs(-1,1,1,-1)
irq_alloc_descs
690 #define irq_alloc_descs(irq, from, cnt, node) \
691 __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
//__irq_alloc_descs(-1,1,1,-1,THIS_MODULE)
__irq_alloc_descs
函数作用:
1)从位图数组allocated_irqs中,找到为0的区域,也就是未分配的,其数组索引index(按照bit做索引),作为分配的irq
2)把分配到irq号,作为index,然后在位图数组allocated_irqs从0更新为1,表示irq已经使用
3)为这个irq分配分配中断描述符
419 /**
420 * irq_alloc_descs - allocate and initialize a range of irq descriptors
421 * @irq: Allocate for specific irq number if irq >= 0
422 * @from: Start the search from this irq number
423 * @cnt: Number of consecutive irqs to allocate.
424 * @node: Preferred node on which the irq descriptor should be allocated
425 * @owner: Owning module (can be NULL)
426 *
427 * Returns the first irq number or error code
428 */
429 int __ref
430 __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
431 struct module *owner)
432 {
433 int start, ret;
434
435 if (!cnt)
436 return -EINVAL;
437
438 if (irq >= 0) {
439 if (from > irq)
440 return -EINVAL;
441 from = irq;
442 } else {
443 /*
444 * For interrupts which are freely allocated the
445 * architecture can force a lower bound to the @from
446 * argument. x86 uses this to exclude the GSI space.
447 */
448 from = arch_dynirq_lower_bound(from);
449 }
450
451 mutex_lock(&sparse_irq_lock);
452
453 start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
454 from, cnt, 0);
//从位图数组allocated_irqs中,找到为0的区域,也就是未分配的,作为其irq的数值
455 ret = -EEXIST;
456 if (irq >=0 && start != irq)
457 goto err;
458
459 if (start + cnt > nr_irqs) {
460 ret = irq_expand_nr_irqs(start + cnt);
461 if (ret)
462 goto err;
463 }
464
465 bitmap_set(allocated_irqs, start, cnt);
//把分配到irq号,作为index,然后在位图数组allocated_irqs从0更新为1,表示irq已经使用。
466 mutex_unlock(&sparse_irq_lock);
//为这个irq分配分配中断描述符
467 return alloc_descs(start, cnt, node, owner);
468
469 err:
470 mutex_unlock(&sparse_irq_lock);
471 return ret;
472 }
473 EXPORT_SYMBOL_GPL(__irq_alloc_descs);
alloc_descs
步骤:
1)对每个irq分配desc资源。
2)把irq和对应的资源放入irq_desc_tree(radix)树中。
195 static int alloc_descs(unsigned int start, unsigned int cnt, int node,
196 struct module *owner)
197 {
198 struct irq_desc *desc;
199 int i;
200
201 for (i = 0; i < cnt; i++) {
202 desc = alloc_desc(start + i, node, owner);
203 if (!desc)
204 goto err;
205 mutex_lock(&sparse_irq_lock);
206 irq_insert_desc(start + i, desc);
//就是把irq和desc插入到irq_desc_tree树中
//104 static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
//106 static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
//107 {
//108 radix_tree_insert(&irq_desc_tree, irq, desc);
//109 }
207 mutex_unlock(&sparse_irq_lock);
208 }
209 return start;
210
211 err:
212 for (i--; i >= 0; i--)
213 free_desc(start + i);
214
215 mutex_lock(&sparse_irq_lock);
216 bitmap_clear(allocated_irqs, start, cnt);
217 mutex_unlock(&sparse_irq_lock);
218 return -ENOMEM;
219 }
在202行调用的alloc_desc函数的定义如下:
alloc_desc
1)分配desc结构体。
2)调用desc_set_defaults函数来初始化desc。
144 static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
145 {
146 struct irq_desc *desc;
147 gfp_t gfp = GFP_KERNEL;
148
149 desc = kzalloc_node(sizeof(*desc), gfp, node);
150 if (!desc)
151 return NULL;
152 /* allocate based on nr_cpu_ids */
153 desc->kstat_irqs = alloc_percpu(unsigned int);
154 if (!desc->kstat_irqs)
155 goto err_desc;
156
157 if (alloc_masks(desc, gfp, node))
158 goto err_kstat;
159
160 raw_spin_lock_init(&desc->lock);
161 lockdep_set_class(&desc->lock, &irq_desc_lock_class);
162
163 desc_set_defaults(irq, desc, node, owner);
164
165 return desc;
166
167 err_kstat:
168 free_percpu(desc->kstat_irqs);
169 err_desc:
170 kfree(desc);
171 return NULL;
172 }
desc_set_defaults
说明:
- desc->irq_data.irq = irq : 把irq赋值给desc->irq_data.irq
71 static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
72 struct module *owner)
73 {
74 int cpu;
75
76 desc->irq_common_data.handler_data = NULL;
77 desc->irq_common_data.msi_desc = NULL;
78
79 desc->irq_data.common = &desc->irq_common_data;
80 desc->irq_data.irq = irq;
81 desc->irq_data.chip = &no_irq_chip;
82 desc->irq_data.chip_data = NULL;
83 irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
84 irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
85 desc->handle_irq = handle_bad_irq;
86 desc->depth = 1;
87 desc->irq_count = 0;
88 desc->irqs_unhandled = 0;
89 desc->name = NULL;
90 desc->owner = owner;
91 for_each_possible_cpu(cpu)
92 *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
93 desc_smp_init(desc, node);
94 }