本章主要分析early_irq_init()。
1、代码流:start_kernel()–>early_irq_init();
2、early_irq_init()详解
<kernel/irq/irqdesc.c>
# define IRQ_BITMAP_BITS (NR_IRQS + 8196)
static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);
int __init early_irq_init(void)
{
int i, initcnt, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity(); /* 设置中断默认的亲和性 */
/* Let arch update nr_irqs and return the nr of preallocated irqs */
initcnt = arch_probe_nr_irqs(); /* initcnt=16 */
/* 自测环境输出结果为:NR_IRQS:33024 nr_irqs:456 16 */
printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
nr_irqs = IRQ_BITMAP_BITS;
if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
initcnt = IRQ_BITMAP_BITS;
if (initcnt > nr_irqs)
nr_irqs = initcnt;
for (i = 0; i < initcnt; i++) {
desc = alloc_desc(i, node, NULL); /* 为虚中断号0~15申请中断描述符 */
set_bit(i, allocated_irqs); /* allocated_irqs中每个bit对应一个虚中断号 */
irq_insert_desc(i, desc); /* 将此虚中断号和中断描述符插入radix_tree,建立映射关系*/
}
/* 上述是和架构无关的初始化,下面是架构相关的初始化 */
return arch_early_irq_init();
}
/* 申请中断描述符并初始化,此处结合struct irq_desc结构体定义看方便理解 */
static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
{
struct irq_desc *desc;
gfp_t gfp = GFP_KERNEL;
desc = kzalloc_node(sizeof(*desc), gfp, node);
if (!desc)
return NULL;
/* allocate based on nr_cpu_ids */
desc->kstat_irqs = alloc_percpu(unsigned int); /* @kstat_irqs:irq stats per cpu */
if (!desc->kstat_irqs)
goto err_desc;
if (alloc_masks(desc, gfp, node))
goto err_kstat;
raw_spin_lock_init(&desc->lock);
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
desc_set_defaults(irq, desc, node, owner); /* 设置中断描述符的默认属性,详见下 */
return desc;
err_kstat:
free_percpu(desc->kstat_irqs);
err_desc:
kfree(desc);
return NULL;
}
static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,struct module *owner)
{
int cpu;
desc->irq_common_data.handler_data = NULL;
desc->irq_common_data.msi_desc = NULL;
desc->irq_data.common = &desc->irq_common_data;
desc->irq_data.irq = irq;
desc->irq_data.chip = &no_irq_chip;
desc->irq_data.chip_data = NULL;
irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
desc->handle_irq = handle_bad_irq;
desc->depth = 1;
desc->irq_count = 0;
desc->irqs_unhandled = 0;
desc->name = NULL;
desc->owner = owner;
for_each_possible_cpu(cpu)
*per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
desc_smp_init(desc, node);
}
/* 用基数树来映射虚中断号irq和中断描述符desc之间的对应关系 */
static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
{
radix_tree_insert(&irq_desc_tree, irq, desc);
}
<arch/x86/kernel/apic/vector.c>
int __init arch_early_irq_init(void)
{
init_legacy_irqs(); /* 给虚中断号0~15的中断描述符设置chip_data域 */
/* Allocate a new irq_domain data structure */
x86_vector_domain = irq_domain_add_tree(NULL, &x86_vector_domain_ops,NULL);
BUG_ON(x86_vector_domain == NULL);
irq_set_default_host(x86_vector_domain);
arch_init_msi_domain(x86_vector_domain);
arch_init_htirq_domain(x86_vector_domain);
BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
return arch_early_ioapic_init();
}
static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
static void init_legacy_irqs(void)
{
int i, node = cpu_to_node(0);
struct apic_chip_data *data;
/*
* For legacy IRQ's, start with assigning irq0 to irq15 to
* ISA_IRQ_VECTOR(i) for all cpu's.
*/
for (i = 0; i < nr_legacy_irqs(); i++) {
data = legacy_irq_data[i] = alloc_apic_chip_data(node);
BUG_ON(!data);
data->cfg.vector = ISA_IRQ_VECTOR(i);
cpumask_setall(data->domain);
irq_set_chip_data(i, data); /* 设置irq对应的desc的chip_data域 */
}
}
<kernel/irq/chip.c>
int irq_set_chip_data(unsigned int irq, void *data)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return -EINVAL;
desc->irq_data.chip_data = data;
irq_put_desc_unlock(desc, flags);
return 0;
}
<arch/x86/kernel/apic/io_apic.c>
int __init arch_early_ioapic_init(void)
{
int i;
if (!nr_legacy_irqs())
io_apic_irqs = ~0UL;
for_each_ioapic(i)
alloc_ioapic_saved_registers(i);
return 0;
}