本文共 6726 字,大约阅读时间需要 22 分钟。
中断控制器描述符定义
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.csdn.net/sinat_20184565/article/details/98095894x86架构下Linux中断IDT建立及中断处理过程之1 博客不错
https://blog.csdn.net/baidu_31504167/article/details/100556391x86架构下Linux中断处理之request_irq
https://blog.csdn.net/baidu_31504167/article/details/101712674early_irq_init
https://blog.csdn.net/wuye110/article/details/78556622x86架构下Linux中断处理之early_irq_init
https://blog.csdn.net/baidu_31504167/article/details/101673798ARM-Linux中断系统