📄 iosapic.c
字号:
goto out; } if (--rte->refcnt > 0) goto out; /* Mask the interrupt */ low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); /* Remove the rte entry from the list */ list_del(&rte->rte_list); iosapic_intr_info[vector].count--; iosapic_free_rte(rte); index = find_iosapic(gsi); iosapic_lists[index].rtes_inuse--; WARN_ON(iosapic_lists[index].rtes_inuse < 0); trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; dest = iosapic_intr_info[vector].dest; printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), cpu_logical_id(dest), dest, vector); if (list_empty(&iosapic_intr_info[vector].rtes)) { /* Sanity check */ BUG_ON(iosapic_intr_info[vector].count); /* Clear the interrupt controller descriptor */ idesc->handler = &no_irq_type; /* Clear the interrupt information */ memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); if (idesc->action) { printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); WARN_ON(1); } /* Free the interrupt vector */ free_irq_vector(vector); } } out: spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&idesc->lock, flags);}/* * 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); if (vector < 0) panic("%s: out of interrupt vectors!\n", __FUNCTION__); 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(gsi, 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 = cpu_physical_id(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(gsi, 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].low32 = IOSAPIC_MASK; INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* 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); }}static inline intiosapic_alloc (void){ int index; for (index = 0; index < NR_IOSAPICS; index++) if (!iosapic_lists[index].addr) return index; printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); return -1;}static inline voidiosapic_free (int index){ memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));}static inline intiosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver){ int index; unsigned int gsi_end, base, end; /* check gsi range */ gsi_end = gsi_base + ((ver >> 16) & 0xff); for (index = 0; index < NR_IOSAPICS; index++) { if (!iosapic_lists[index].addr) continue; base = iosapic_lists[index].gsi_base; end = base + iosapic_lists[index].num_rte - 1; if (gsi_base < base && gsi_end < base) continue;/* OK */ if (gsi_base > end && gsi_end > end) continue; /* OK */ return -EBUSY; } return 0;}int __devinitiosapic_init (unsigned long phys_addr, unsigned int gsi_base){ int num_rte, err, index; unsigned int isa_irq, ver; char __iomem *addr; unsigned long flags; spin_lock_irqsave(&iosapic_lock, flags); { addr = ioremap(phys_addr, 0); ver = iosapic_version(addr); if ((err = iosapic_check_gsi_range(gsi_base, ver))) { iounmap(addr); spin_unlock_irqrestore(&iosapic_lock, flags); return err; } /* * 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; index = iosapic_alloc(); iosapic_lists[index].addr = addr; iosapic_lists[index].gsi_base = gsi_base; iosapic_lists[index].num_rte = num_rte;#ifdef CONFIG_NUMA iosapic_lists[index].node = MAX_NUMNODES;#endif } spin_unlock_irqrestore(&iosapic_lock, flags); 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); } return 0;}#ifdef CONFIG_HOTPLUGintiosapic_remove (unsigned int gsi_base){ int index, err = 0; unsigned long flags; spin_lock_irqsave(&iosapic_lock, flags); { index = find_iosapic(gsi_base); if (index < 0) { printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", __FUNCTION__, gsi_base); goto out; } if (iosapic_lists[index].rtes_inuse) { err = -EBUSY; printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", __FUNCTION__, gsi_base); goto out; } iounmap(iosapic_lists[index].addr); iosapic_free(index); } out: spin_unlock_irqrestore(&iosapic_lock, flags); return err;}#endif /* CONFIG_HOTPLUG */#ifdef CONFIG_NUMAvoid __devinitmap_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#ifndef XENstatic int __init iosapic_enable_kmalloc (void){ iosapic_kmalloc_ok = 1; return 0;}core_initcall (iosapic_enable_kmalloc);#endif#ifdef XEN/* nop for now */void set_irq_affinity_info(unsigned int irq, int hwid, int redir) {}static int iosapic_physbase_to_id(unsigned long physbase){ int i; unsigned long addr = physbase | __IA64_UNCACHED_OFFSET; for (i = 0; i < NR_IOSAPICS; i++) { if ((unsigned long)(iosapic_lists[i].addr) == addr) return i; } return -1;}int iosapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval){ int id; unsigned long flags; if ((id = (iosapic_physbase_to_id(physbase))) < 0) return id; spin_lock_irqsave(&iosapic_lock, flags); *pval = iosapic_read(iosapic_lists[id].addr, reg); spin_unlock_irqrestore(&iosapic_lock, flags); return 0;}int iosapic_guest_write(unsigned long physbase, unsigned int reg, u32 val){ unsigned int id, gsi, vec, xen_vec, dest, high32; char rte_index; struct iosapic *ios; struct iosapic_intr_info *info; struct rte_entry rte; unsigned long flags; if ((id = (iosapic_physbase_to_id(physbase))) < 0) return -EINVAL; ios = &iosapic_lists[id]; /* Only handle first half of RTE update */ if ((reg < 0x10) || (reg & 1)) return 0; rte.val = val; rte_index = IOSAPIC_RTEINDEX(reg); vec = rte.lo.vector;#if 0 /* Take PMI/NMI/INIT/EXTINT handled by xen */ if (rte.delivery_mode > IOSAPIC_LOWEST_PRIORITY) { printk("Attempt to write IOSAPIC dest mode owned by xen!\n"); printk("IOSAPIC/PIN = (%d/%d), lo = 0x%x\n", id, rte_index, val); return -EINVAL; }#endif /* Sanity check. Vector should be allocated before this update */ if ((rte_index > ios->num_rte) || ((vec > IA64_FIRST_DEVICE_VECTOR) && (vec < IA64_LAST_DEVICE_VECTOR) && (!test_bit(vec - IA64_FIRST_DEVICE_VECTOR, ia64_vector_mask)))) return -EINVAL; gsi = ios->gsi_base + rte_index; xen_vec = gsi_to_vector(gsi); if (xen_vec >= 0 && test_bit(xen_vec, ia64_xen_vector)) { printk("WARN: GSI %d in use by Xen.\n", gsi); return -EINVAL; } info = &iosapic_intr_info[vec]; spin_lock_irqsave(&irq_descp(vec)->lock, flags); spin_lock(&iosapic_lock); if (!gsi_vector_to_rte(gsi, vec)) { register_intr(gsi, vec, IOSAPIC_LOWEST_PRIORITY, rte.lo.polarity, rte.lo.trigger); } else if (vector_is_shared(vec)) { if ((info->trigger != rte.lo.trigger) || (info->polarity != rte.lo.polarity)) { printk("WARN: can't override shared interrupt vec\n"); printk("IOSAPIC/PIN = (%d/%d), ori = 0x%x, new = 0x%x\n", id, rte_index, info->low32, rte.val); spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&irq_descp(vec)->lock, flags); return -EINVAL; } /* If the vector is shared and already unmasked for other * interrupt sources, don't mask it. * * Same check may also apply to single gsi pin, which may * be shared by devices belonging to different domain. But * let's see how to act later on demand. */ if (!(info->low32 & IOSAPIC_MASK)) rte.lo.mask = 0; } /* time to update physical RTE */ dest = cpu_physical_id(smp_processor_id()); high32 = (dest << IOSAPIC_DEST_SHIFT); iosapic_write(iosapic_lists[id].addr, reg + 1, high32); iosapic_write(iosapic_lists[id].addr, reg, rte.val); info->low32 = rte.val; info->dest = dest; spin_unlock(&iosapic_lock); spin_unlock_irqrestore(&irq_descp(vec)->lock, flags); return 0;}#endif /* XEN */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -