慢慢欣赏linux 中断学习之外部中断 arm实现

2021/5/3 7:25:23

本文主要是介绍慢慢欣赏linux 中断学习之外部中断 arm实现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

void __init init_IRQ(void)
{
	if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
		irqchip_init();
	else
		machine_desc->init_irq();
		==>{
			DT_MACHINE_START(CNS3XXX_DT, "Cavium Networks CNS3xxx")
				.dt_compat	= cns3xxx_dt_compat,
				.map_io		= cns3xxx_map_io,
				.init_irq	= cns3xxx_init_irq,
				=>/* used by entry-macro.S */
				void __init cns3xxx_init_irq(void)
				{
					gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
						 IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
					=>void __init gic_init(unsigned int gic_nr, int irq_start,
								 void __iomem *dist_base, void __iomem *cpu_base)
					{
						struct gic_chip_data *gic = &gic_data[gic_nr];
						gic->raw_dist_base = dist_base;
						gic->raw_cpu_base = cpu_base;

						__gic_init_bases(gic, irq_start, NULL);
						=>int __init __gic_init_bases(struct gic_chip_data *gic,
										   int irq_start,
										   struct fwnode_handle *handle)
						{
							if (gic == &gic_data[0]) {
								/*
								 * Initialize the CPU interface map to all CPUs.
								 * It will be refined as each CPU probes its ID.
								 * This is only necessary for the primary GIC.
								 */
								for (i = 0; i < NR_GIC_CPU_IF; i++)
									gic_cpu_map[i] = 0xff;
								set_smp_cross_call(gic_raise_softirq);
								cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
											  "irqchip/arm/gic:starting",
											  gic_starting_cpu, NULL);
								set_handle_irq(gic_handle_irq);
							}

							if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) {
								name = kasprintf(GFP_KERNEL, "GICv2");
								gic_init_chip(gic, NULL, name, true);
							} else {
								name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic-&gic_data[0]));
								gic_init_chip(gic, NULL, name, false);
							}

							ret = gic_init_bases(gic, irq_start, handle);
							=>int gic_init_bases(struct gic_chip_data *gic, int irq_start,
										  struct fwnode_handle *handle)
							{
								irq_hw_number_t hwirq_base;
								int gic_irqs, irq_base, ret;

								if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
									/* Frankein-GIC without banked registers... */
									unsigned int cpu;

									gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
									gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);

									for_each_possible_cpu(cpu) {
										u32 mpidr = cpu_logical_map(cpu);
										u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
										unsigned long offset = gic->percpu_offset * core_id;
										*per_cpu_ptr(gic->dist_base.percpu_base, cpu) =
											gic->raw_dist_base + offset;
										*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) =
											gic->raw_cpu_base + offset;
									}

									gic_set_base_accessor(gic, gic_get_percpu_base);
								} else {
									/* Normal, sane GIC... */
									WARN(gic->percpu_offset,
										 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
										 gic->percpu_offset);
									gic->dist_base.common_base = gic->raw_dist_base;
									gic->cpu_base.common_base = gic->raw_cpu_base;
									gic_set_base_accessor(gic, gic_get_common_base);
								}

								/*
								 * Find out how many interrupts are supported.
								 * The GIC only supports up to 1020 interrupt sources.
								 */
								gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
								gic_irqs = (gic_irqs + 1) * 32;
								if (gic_irqs > 1020)
									gic_irqs = 1020;
								gic->gic_irqs = gic_irqs;

								if (handle) {		/* DT/ACPI */
									gic->domain = irq_domain_create_linear(handle, gic_irqs,
														   &gic_irq_domain_hierarchy_ops,
														   gic);
								} else {		/* Legacy support */
									/*
									 * For primary GICs, skip over SGIs.
									 * For secondary GICs, skip over PPIs, too.
									 */
									if (gic == &gic_data[0] && (irq_start & 31) > 0) {
										hwirq_base = 16;
										if (irq_start != -1)
											irq_start = (irq_start & ~31) + 16;
									} else {
										hwirq_base = 32;
									}

									gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */

									irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
												   numa_node_id());
									if (irq_base < 0) {
										WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
											 irq_start);
										irq_base = irq_start;
									}

									gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base,
												hwirq_base, &gic_irq_domain_ops, gic);
									=>struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
														 unsigned int size,
														 unsigned int first_irq,
														 irq_hw_number_t first_hwirq,
														 const struct irq_domain_ops *ops,
														 void *host_data)
									{
										struct irq_domain *domain;

										domain = __irq_domain_add(of_node_to_fwnode(of_node), first_hwirq + size,
													  first_hwirq + size, 0, ops, host_data);
										if (domain)
											irq_domain_associate_many(domain, first_irq, first_hwirq, size);
											=>void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
															   irq_hw_number_t hwirq_base, int count)
											{
												struct device_node *of_node;
												int i;

												of_node = irq_domain_get_of_node(domain);

												for (i = 0; i < count; i++) {
													irq_domain_associate(domain, irq_base + i, hwirq_base + i);
													=>int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
																 irq_hw_number_t hwirq)
													{
														struct irq_data *irq_data = irq_get_irq_data(virq);
														int ret;

														irq_data->hwirq = hwirq;
														irq_data->domain = domain;
														if (domain->ops->map) {
															ret = domain->ops->map(domain, virq, hwirq);

															/* If not already assigned, give the domain the chip's name */
															if (!domain->name && irq_data->chip)
																domain->name = irq_data->chip->name;
														}

														domain->mapcount++;
														irq_domain_set_mapping(domain, hwirq, irq_data);
														=>void irq_domain_set_mapping(struct irq_domain *domain,
																		   irq_hw_number_t hwirq,
																		   struct irq_data *irq_data)
														{
															if (hwirq < domain->revmap_size) {
																domain->linear_revmap[hwirq] = irq_data->irq;
															} else {
																mutex_lock(&domain->revmap_tree_mutex);
																radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
																mutex_unlock(&domain->revmap_tree_mutex);
															}
														}

														irq_clear_status_flags(virq, IRQ_NOREQUEST);

														return 0;
													}

												}
											}

										return domain;
									}
								}

								gic_dist_init(gic);
								ret = gic_cpu_init(gic);

								ret = gic_pm_init(gic);

								return 0;

								return ret;
							}


							return ret;
						}
					}

				}
			MACHINE_END
		}
]

 



这篇关于慢慢欣赏linux 中断学习之外部中断 arm实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程