中断控制器描述符定义
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
初始化流程
int __init early_irq_init(void)
{
desc = irq_desc;
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) {
desc[i].kstat_irqs = alloc_percpu(unsigned int);
alloc_masks(&desc[i], node);
raw_spin_lock_init(&desc[i].lock);
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
desc_set_defaults(i, &desc[i], node, NULL, NULL);
}
return arch_early_irq_init();
=>int __init arch_early_irq_init(void)
{
struct fwnode_handle *fn = irq_domain_alloc_named_fwnode("VECTOR");
x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
NULL);
=>static const struct irq_domain_ops x86_vector_domain_ops = {
.alloc = x86_vector_alloc_irqs,
.free = x86_vector_free_irqs,
.activate = x86_vector_activate,
.deactivate = x86_vector_deactivate,
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
.debug_show = x86_vector_debug_show,
#endif
};
=>static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
struct irq_alloc_info *info = arg;
struct apic_chip_data *apicd;
struct irq_data *irqd;
int i, err, node;
for (i = 0; i < nr_irqs; i++) {
irqd = irq_domain_get_irq_data(domain, virq + i);
node = irq_data_get_node(irqd);
WARN_ON_ONCE(irqd->chip_data);
apicd = alloc_apic_chip_data(node);
apicd->irq = virq + i;
irqd->chip = &lapic_controller;
irqd->chip_data = apicd;
irqd->hwirq = virq + i;
irqd_set_single_target(irqd);
/*
* Legacy vectors are already assigned when the IOAPIC
* takes them over. They stay on the same vector. This is
* required for check_timer() to work correctly as it might
* switch back to legacy mode. Only update the hardware
* config.
*/
if (info->flags & X86_IRQ_ALLOC_LEGACY) {
if (!vector_configure_legacy(virq + i, irqd, apicd))
continue;
}
err = assign_irq_vector_policy(irqd, info);
=>static int
assign_irq_vector_policy(struct irq_data *irqd, struct irq_alloc_info *info)
{
if (irqd_affinity_is_managed(irqd))
return reserve_managed_vector(irqd);
if (info->mask)
return assign_irq_vector(irqd, info->mask);
=>static int assign_irq_vector(struct irq_data *irqd, const struct cpumask *dest)
{
unsigned long flags;
int ret;
raw_spin_lock_irqsave(&vector_lock, flags);
cpumask_and(vector_searchmask, dest, cpu_online_mask);
ret = assign_vector_locked(irqd, vector_searchmask);
=>static int assign_vector_locked(struct irq_data *irqd,
const struct cpumask *dest)
{
struct apic_chip_data *apicd = apic_chip_data(irqd);
int vector = allocate_vector(irqd, dest);
=>static int allocate_vector(struct irq_data *irqd, const struct cpumask *dest)
{
struct apic_chip_data *apicd = apic_chip_data(irqd);
bool resvd = apicd->has_reserved;
unsigned int cpu = apicd->cpu;
int vector = apicd->vector;
lockdep_assert_held(&vector_lock);
/*
* If the current target CPU is online and in the new requested
* affinity mask, there is no point in moving the interrupt from
* one CPU to another.
*/
if (vector && cpu_online(cpu) && cpumask_test_cpu(cpu, dest))
return 0;
vector = irq_matrix_alloc(vector_matrix, dest, resvd, &cpu);
if (vector > 0)
apic_update_vector(irqd, vector, cpu);
=>static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
unsigned int newcpu)
{
struct apic_chip_data *apicd = apic_chip_data(irqd);
struct irq_desc *desc = irq_data_to_desc(irqd);
bool managed = irqd_affinity_is_managed(irqd);
/*
* If there is no vector associated or if the associated vector is
* the shutdown vector, which is associated to make PCI/MSI
* shutdown mode work, then there is nothing to release. Clear out
* prev_vector for this and the offlined target case.
*/
apicd->prev_vector = 0;
if (!apicd->vector || apicd->vector == MANAGED_IRQ_SHUTDOWN_VECTOR)
goto setnew;
/*
* If the target CPU of the previous vector is online, then mark
* the vector as move in progress and store it for cleanup when the
* first interrupt on the new vector arrives. If the target CPU is
* offline then the regular release mechanism via the cleanup
* vector is not possible and the vector can be immediately freed
* in the underlying matrix allocator.
*/
if (cpu_online(apicd->cpu)) {
apicd->move_in_progress = true;
apicd->prev_vector = apicd->vector;
apicd->prev_cpu = apicd->cpu;
} else {
irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
managed);
}
setnew:
apicd->vector = newvec;
apicd->cpu = newcpu;
BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));
per_cpu(vector_irq, newcpu)[newvec] = desc; // vector_irq与中断控制器描述符联系起来
}
return vector;
}
apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
return 0;
}
raw_spin_unlock_irqrestore(&vector_lock, flags);
return ret;
}
/*
* Make only a global reservation with no guarantee. A real vector
* is associated at activation time.
*/
return reserve_irq_vector(irqd);
}
}
return 0;
}
irq_domain_free_fwnode(fn);
irq_set_default_host(x86_vector_domain);
arch_init_msi_domain(x86_vector_domain);
/*
* Allocate the vector matrix allocator data structure and limit the
* search area.
*/
vector_matrix = irq_alloc_matrix(NR_VECTORS, FIRST_EXTERNAL_VECTOR,
FIRST_SYSTEM_VECTOR);
return arch_early_ioapic_init();
}
}
linux驱动中断不能睡眠的原因
http://blog.chinaunix.net/uid-24866549-id-4611653.html
内核IRQ中断向量
https://blog.youkuaiyun.com/sinat_20184565/article/details/98095894
x86架构下Linux中断IDT建立及中断处理过程之1 博客不错
https://blog.youkuaiyun.com/baidu_31504167/article/details/100556391
x86架构下Linux中断处理之request_irq
https://blog.youkuaiyun.com/baidu_31504167/article/details/101712674
early_irq_init
https://blog.youkuaiyun.com/wuye110/article/details/78556622
x86架构下Linux中断处理之early_irq_init
https://blog.youkuaiyun.com/baidu_31504167/article/details/101673798
ARM-Linux中断系统
https://www.cnblogs.com/arnoldlu/p/7406441.html