iosapic.c
来自「h内核」· C语言 代码 · 共 829 行 · 第 1/2 页
C
829 行
* { * unsigned int version : 8; * unsigned int reserved1 : 8; * unsigned int max_redir : 8; * unsigned int reserved2 : 8; * } */ return iosapic_read(addr, IOSAPIC_VERSION);}/* * if the given vector is already owned by other, * assign a new vector for the other and make the vector available */static void __initiosapic_reassign_vector (int vector){ int new_vector; if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger) { new_vector = assign_irq_vector(AUTO_ASSIGN); printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], sizeof(struct iosapic_intr_info)); memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); iosapic_intr_info[vector].rte_index = -1; }}static voidregister_intr (unsigned int gsi, int vector, unsigned char delivery, unsigned long polarity, unsigned long trigger){ irq_desc_t *idesc; struct hw_interrupt_type *irq_type; int rte_index; int index; unsigned long gsi_base; void __iomem *iosapic_address; index = find_iosapic(gsi); if (index < 0) { printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi); return; } iosapic_address = iosapic_lists[index].addr; gsi_base = iosapic_lists[index].gsi_base; rte_index = gsi - gsi_base; iosapic_intr_info[vector].rte_index = rte_index; iosapic_intr_info[vector].polarity = polarity; iosapic_intr_info[vector].dmode = delivery; iosapic_intr_info[vector].addr = iosapic_address; iosapic_intr_info[vector].gsi_base = gsi_base; iosapic_intr_info[vector].trigger = trigger; iosapic_intr_info[vector].refcnt++; if (trigger == IOSAPIC_EDGE) irq_type = &irq_type_iosapic_edge; else irq_type = &irq_type_iosapic_level; idesc = irq_descp(vector); if (idesc->handler != irq_type) { if (idesc->handler != &no_irq_type) printk(KERN_WARNING "%s: changing vector %d from %s to %s\n", __FUNCTION__, vector, idesc->handler->typename, irq_type->typename); idesc->handler = irq_type; }}static unsigned intget_target_cpu (unsigned int gsi, int vector){#ifdef CONFIG_SMP static int cpu = -1; /* * If the platform supports redirection via XTP, let it * distribute interrupts. */ if (smp_int_redirect & SMP_IRQ_REDIRECTION) return hard_smp_processor_id(); /* * Some interrupts (ACPI SCI, for instance) are registered * before the BSP is marked as online. */ if (!cpu_online(smp_processor_id())) return hard_smp_processor_id();#ifdef CONFIG_NUMA { int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; cpumask_t cpu_mask; iosapic_index = find_iosapic(gsi); if (iosapic_index < 0 || iosapic_lists[iosapic_index].node == MAX_NUMNODES) goto skip_numa_setup; cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node); for_each_cpu_mask(numa_cpu, cpu_mask) { if (!cpu_online(numa_cpu)) cpu_clear(numa_cpu, cpu_mask); } num_cpus = cpus_weight(cpu_mask); if (!num_cpus) goto skip_numa_setup; /* Use vector assigment to distribute across cpus in node */ cpu_index = vector % num_cpus; for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) numa_cpu = next_cpu(numa_cpu, cpu_mask); if (numa_cpu != NR_CPUS) return cpu_physical_id(numa_cpu); }skip_numa_setup:#endif /* * Otherwise, round-robin interrupt vectors across all the * processors. (It'd be nice if we could be smarter in the * case of NUMA.) */ do { if (++cpu >= NR_CPUS) cpu = 0; } while (!cpu_online(cpu)); return cpu_physical_id(cpu);#else return hard_smp_processor_id();#endif}/* * ACPI can describe IOSAPIC interrupts via static tables and namespace * methods. This provides an interface to register those interrupts and * program the IOSAPIC RTE. */intiosapic_register_intr (unsigned int gsi, unsigned long polarity, unsigned long trigger){ int vector; unsigned int dest; unsigned long flags; /* * If this GSI has already been registered (i.e., it's a * shared interrupt, or we lost a race to register it), * don't touch the RTE. */ spin_lock_irqsave(&iosapic_lock, flags); { vector = gsi_to_vector(gsi); if (vector > 0) { iosapic_intr_info[vector].refcnt++; spin_unlock_irqrestore(&iosapic_lock, flags); return vector; } vector = assign_irq_vector(AUTO_ASSIGN); dest = get_target_cpu(gsi, vector); register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); set_rte(vector, dest, 1); } spin_unlock_irqrestore(&iosapic_lock, flags); printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), cpu_logical_id(dest), dest, vector); return vector;}#ifdef CONFIG_ACPI_DEALLOCATE_IRQvoidiosapic_unregister_intr (unsigned int gsi){ unsigned long flags; int irq, vector; irq_desc_t *idesc; int rte_index; unsigned long trigger, polarity; /* * If the irq associated with the gsi is not found, * iosapic_unregister_intr() is unbalanced. We need to check * this again after getting locks. */ irq = gsi_to_irq(gsi); if (irq < 0) { printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); WARN_ON(1); return; } vector = irq_to_vector(irq); idesc = irq_descp(irq); spin_lock_irqsave(&idesc->lock, flags); spin_lock(&iosapic_lock); { rte_index = iosapic_intr_info[vector].rte_index; if (rte_index < 0) { spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags); printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); WARN_ON(1); return; } if (--iosapic_intr_info[vector].refcnt > 0) { spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags); return; } /* * If interrupt handlers still exist on the irq * associated with the gsi, don't unregister the * interrupt. */ if (idesc->action) { iosapic_intr_info[vector].refcnt++; spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags); printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq); return; } /* Clear the interrupt controller descriptor. */ idesc->handler = &no_irq_type; trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; /* Clear the interrupt information. */ memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ } spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags); /* Free the interrupt vector */ free_irq_vector(vector); printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n", gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), vector);}#endif /* CONFIG_ACPI_DEALLOCATE_IRQ *//* * ACPI calls this when it finds an entry for a platform interrupt. * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */int __initiosapic_register_platform_intr (u32 int_type, unsigned int gsi, int iosapic_vector, u16 eid, u16 id, unsigned long polarity, unsigned long trigger){ static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"}; unsigned char delivery; int vector, mask = 0; unsigned int dest = ((id << 8) | eid) & 0xffff; switch (int_type) { case ACPI_INTERRUPT_PMI: vector = iosapic_vector; /* * since PMI vector is alloc'd by FW(ACPI) not by kernel, * we need to make sure the vector is available */ iosapic_reassign_vector(vector); delivery = IOSAPIC_PMI; break; case ACPI_INTERRUPT_INIT: vector = assign_irq_vector(AUTO_ASSIGN); delivery = IOSAPIC_INIT; break; case ACPI_INTERRUPT_CPEI: vector = IA64_CPE_VECTOR; delivery = IOSAPIC_LOWEST_PRIORITY; mask = 1; break; default: printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type); return -1; } register_intr(gsi, vector, delivery, polarity, trigger); printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), cpu_logical_id(dest), dest, vector); set_rte(vector, dest, mask); return vector;}/* * ACPI calls this when it finds an entry for a legacy ISA IRQ override. * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). */void __initiosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, unsigned long polarity, unsigned long trigger){ int vector; unsigned int dest = hard_smp_processor_id(); vector = isa_irq_to_vector(isa_irq); register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n", isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level", polarity == IOSAPIC_POL_HIGH ? "high" : "low", cpu_logical_id(dest), dest, vector); set_rte(vector, dest, 1);}void __initiosapic_system_init (int system_pcat_compat){ int vector; for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ pcat_compat = system_pcat_compat; if (pcat_compat) { /* * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support * enabled. */ printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); outb(0xff, 0xA1); outb(0xff, 0x21); }}void __initiosapic_init (unsigned long phys_addr, unsigned int gsi_base){ int num_rte; unsigned int isa_irq, ver; char __iomem *addr; addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); /* * The MAX_REDIR register holds the highest input pin * number (starting from 0). * We add 1 so that we can use it for number of pins (= RTEs) */ num_rte = ((ver >> 16) & 0xff) + 1; iosapic_lists[num_iosapic].addr = addr; iosapic_lists[num_iosapic].gsi_base = gsi_base; iosapic_lists[num_iosapic].num_rte = num_rte;#ifdef CONFIG_NUMA iosapic_lists[num_iosapic].node = MAX_NUMNODES;#endif num_iosapic++; if ((gsi_base == 0) && pcat_compat) { /* * Map the legacy ISA devices into the IOSAPIC data. Some of these may * get reprogrammed later on with data from the ACPI Interrupt Source * Override table. */ for (isa_irq = 0; isa_irq < 16; ++isa_irq) iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); }}#ifdef CONFIG_NUMAvoid __initmap_iosapic_to_node(unsigned int gsi_base, int node){ int index; index = find_iosapic(gsi_base); if (index < 0) { printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi_base); return; } iosapic_lists[index].node = node; return;}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?