慢慢欣赏linux 继续深入学习x86中断

中断控制器描述符定义

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/98095894

x86架构下Linux中断IDT建立及中断处理过程之1    博客不错
https://blog.csdn.net/baidu_31504167/article/details/100556391

x86架构下Linux中断处理之request_irq
https://blog.csdn.net/baidu_31504167/article/details/101712674

early_irq_init
https://blog.csdn.net/wuye110/article/details/78556622

x86架构下Linux中断处理之early_irq_init
https://blog.csdn.net/baidu_31504167/article/details/101673798

ARM-Linux中断系统
https://www.cnblogs.com/arnoldlu/p/7406441.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值