📄 io_apic_32.c
字号:
pin = find_isa_irq_pin(8, mp_INT); if (pin == -1) { WARN_ON_ONCE(1); return; } apic = find_isa_irq_apic(8, mp_INT); if (apic == -1) { WARN_ON_ONCE(1); return; } entry0 = ioapic_read_entry(apic, pin); clear_IO_APIC_pin(apic, pin); memset(&entry1, 0, sizeof(entry1)); entry1.dest_mode = 0; /* physical delivery */ entry1.mask = 0; /* unmask IRQ now */ entry1.dest.physical.physical_dest = hard_smp_processor_id(); entry1.delivery_mode = dest_ExtINT; entry1.polarity = entry0.polarity; entry1.trigger = 0; entry1.vector = 0; ioapic_write_entry(apic, pin, entry1); save_control = CMOS_READ(RTC_CONTROL); save_freq_select = CMOS_READ(RTC_FREQ_SELECT); CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6, RTC_FREQ_SELECT); CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL); i = 100; while (i-- > 0) { mdelay(10); if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF) i -= 10; } CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); clear_IO_APIC_pin(apic, pin); ioapic_write_entry(apic, pin, entry0);}int timer_uses_ioapic_pin_0;/* * This code may look a bit paranoid, but it's supposed to cooperate with * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast * fanatically on his truly buggy board. */static inline void __init check_timer(void){ int apic1, pin1, apic2, pin2; int vector; unsigned long flags; local_irq_save(flags); /* * get/set the timer IRQ vector: */ disable_8259A_irq(0); vector = assign_irq_vector(0); set_intr_gate(vector, interrupt[0]); /* * Subtle, code in do_timer_interrupt() expects an AEOI * mode for the 8259A whenever interrupts are routed * through I/O APICs. Also IRQ0 has to be enabled in * the 8259A which implies the virtual wire has to be * disabled in the local APIC. */ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); timer_ack = 1; if (timer_over_8254 > 0) enable_8259A_irq(0); pin1 = find_isa_irq_pin(0, mp_INT); apic1 = find_isa_irq_apic(0, mp_INT); pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; if (pin1 == 0) timer_uses_ioapic_pin_0 = 1; printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", vector, apic1, pin1, apic2, pin2); if (pin1 != -1) { /* * Ok, does IRQ0 through the IOAPIC work? */ unmask_IO_APIC_irq(0); if (timer_irq_works()) { if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); setup_nmi(); enable_8259A_irq(0); } if (disable_timer_pin_1 > 0) clear_IO_APIC_pin(0, pin1); goto out; } clear_IO_APIC_pin(apic1, pin1); printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to " "IO-APIC\n"); } printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); if (pin2 != -1) { printk("\n..... (found pin %d) ...", pin2); /* * legacy devices should be connected to IO APIC #0 */ setup_ExtINT_IRQ0_pin(apic2, pin2, vector); if (timer_irq_works()) { printk("works.\n"); if (pin1 != -1) replace_pin_at_irq(0, apic1, pin1, apic2, pin2); else add_pin_to_irq(0, apic2, pin2); if (nmi_watchdog == NMI_IO_APIC) { setup_nmi(); } goto out; } /* * Cleanup, just in case ... */ clear_IO_APIC_pin(apic2, pin2); } printk(" failed.\n"); if (nmi_watchdog == NMI_IO_APIC) { printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); nmi_watchdog = 0; } printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq, "fasteoi"); apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ enable_8259A_irq(0); if (timer_irq_works()) { printk(" works.\n"); goto out; } apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); printk(" failed.\n"); printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); timer_ack = 0; init_8259A(0); make_8259A_irq(0); apic_write_around(APIC_LVT0, APIC_DM_EXTINT); unlock_ExtINT_logic(); if (timer_irq_works()) { printk(" works.\n"); goto out; } printk(" failed :(.\n"); panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " "report. Then try booting with the 'noapic' option");out: local_irq_restore(flags);}/* * * IRQ's that are handled by the PIC in the MPS IOAPIC case. * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. */#define PIC_IRQS (1 << PIC_CASCADE_IR)void __init setup_IO_APIC(void){ int i; /* Reserve all the system vectors. */ for (i = FIRST_SYSTEM_VECTOR; i < NR_VECTORS; i++) set_bit(i, used_vectors); enable_IO_APIC(); if (acpi_ioapic) io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ else io_apic_irqs = ~PIC_IRQS; printk("ENABLING IO-APIC IRQs\n"); /* * Set up IO-APIC IRQ routing. */ if (!acpi_ioapic) setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); if (!acpi_ioapic) print_IO_APIC();}static int __init setup_disable_8254_timer(char *s){ timer_over_8254 = -1; return 1;}static int __init setup_enable_8254_timer(char *s){ timer_over_8254 = 2; return 1;}__setup("disable_8254_timer", setup_disable_8254_timer);__setup("enable_8254_timer", setup_enable_8254_timer);/* * Called after all the initialization is done. If we didnt find any * APIC bugs then we can allow the modify fast path */ static int __init io_apic_bug_finalize(void){ if(sis_apic_bug == -1) sis_apic_bug = 0; return 0;}late_initcall(io_apic_bug_finalize);struct sysfs_ioapic_data { struct sys_device dev; struct IO_APIC_route_entry entry[0];};static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];static int ioapic_suspend(struct sys_device *dev, pm_message_t state){ struct IO_APIC_route_entry *entry; struct sysfs_ioapic_data *data; int i; data = container_of(dev, struct sysfs_ioapic_data, dev); entry = data->entry; for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) entry[i] = ioapic_read_entry(dev->id, i); return 0;}static int ioapic_resume(struct sys_device *dev){ struct IO_APIC_route_entry *entry; struct sysfs_ioapic_data *data; unsigned long flags; union IO_APIC_reg_00 reg_00; int i; data = container_of(dev, struct sysfs_ioapic_data, dev); entry = data->entry; spin_lock_irqsave(&ioapic_lock, flags); reg_00.raw = io_apic_read(dev->id, 0); if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; io_apic_write(dev->id, 0, reg_00.raw); } spin_unlock_irqrestore(&ioapic_lock, flags); for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) ioapic_write_entry(dev->id, i, entry[i]); return 0;}static struct sysdev_class ioapic_sysdev_class = { set_kset_name("ioapic"), .suspend = ioapic_suspend, .resume = ioapic_resume,};static int __init ioapic_init_sysfs(void){ struct sys_device * dev; int i, size, error = 0; error = sysdev_class_register(&ioapic_sysdev_class); if (error) return error; for (i = 0; i < nr_ioapics; i++ ) { size = sizeof(struct sys_device) + nr_ioapic_registers[i] * sizeof(struct IO_APIC_route_entry); mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); if (!mp_ioapic_data[i]) { printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); continue; } memset(mp_ioapic_data[i], 0, size); dev = &mp_ioapic_data[i]->dev; dev->id = i; dev->cls = &ioapic_sysdev_class; error = sysdev_register(dev); if (error) { kfree(mp_ioapic_data[i]); mp_ioapic_data[i] = NULL; printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); continue; } } return 0;}device_initcall(ioapic_init_sysfs);/* * Dynamic irq allocate and deallocation */int create_irq(void){ /* Allocate an unused irq */ int irq, new, vector = 0; unsigned long flags; irq = -ENOSPC; spin_lock_irqsave(&vector_lock, flags); for (new = (NR_IRQS - 1); new >= 0; new--) { if (platform_legacy_irq(new)) continue; if (irq_vector[new] != 0) continue; vector = __assign_irq_vector(new); if (likely(vector > 0)) irq = new; break; } spin_unlock_irqrestore(&vector_lock, flags); if (irq >= 0) { set_intr_gate(vector, interrupt[irq]); dynamic_irq_init(irq); } return irq;}void destroy_irq(unsigned int irq){ unsigned long flags; dynamic_irq_cleanup(irq); spin_lock_irqsave(&vector_lock, flags); irq_vector[irq] = 0; spin_unlock_irqrestore(&vector_lock, flags);}/* * MSI message composition */#ifdef CONFIG_PCI_MSIstatic int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg){ int vector; unsigned dest; vector = assign_irq_vector(irq); if (vector >= 0) { dest = cpu_mask_to_apicid(TARGET_CPUS); msg->address_hi = MSI_ADDR_BASE_HI; msg->address_lo = MSI_ADDR_BASE_LO | ((INT_DEST_MODE == 0) ? MSI_ADDR_DEST_MODE_PHYSICAL: MSI_ADDR_DEST_MODE_LOGICAL) | ((INT_DELIVERY_MODE != dest_LowestPrio) ? MSI_ADDR_REDIRECTION_CPU: MSI_ADDR_REDIRECTION_LOWPRI) | MSI_ADDR_DEST_ID(dest); msg->data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | ((INT_DELIVERY_MODE != dest_LowestPrio) ? MSI_DATA_DELIVERY_FIXED: MSI_DATA_DELIVERY_LOWPRI) | MSI_DATA_VECTOR(vector); } return vector;}#ifdef CONFIG_SMPstatic void set_msi_irq_affinity(unsigned int irq, cpumask_t mask){ struct msi_msg msg; unsigned int dest; cpumask_t tmp; int vector; cpus_and(tmp, mask, cpu_online_map); if (cpus_empty(tmp)) tmp = TARGET_CPUS; vector = assign_irq_vector(irq); if (vector < 0) return; dest = cpu_mask_to_apicid(mask); read_msi_msg(irq, &msg); msg.data &= ~MSI_DATA_VECTOR_MASK; msg.data |= MSI_DATA_VECTOR(vector); msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; msg.address_lo |= MSI_ADDR_DEST_ID(dest); write_msi_msg(irq, &msg); irq_desc[irq].affinity = mask;}#endif /* CONFIG_SMP *//* * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, * which implement the MSI or MSI-X Capability Structure. */static struct irq_chip msi_chip = { .name = "PCI-MSI", .unmask = unmask_msi_irq, .mask = mask_msi_irq, .ack = ack_ioapic_irq,#ifdef CONFIG_SMP .set_affinity = set_msi_irq_affinity,#endif .retrigger = ioapic_retrigger_irq,};int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc){ struct msi_msg msg; int irq, ret; irq = create_irq(); if (irq < 0) return irq; ret = msi_compose_msg(dev, irq, &msg); if (ret < 0) { destroy_irq(irq); return ret; } set_irq_msi(irq, desc); write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); return 0;}void arch_teardown_msi_irq(unsigned int irq){ destroy_irq(irq);}#endif /* CONFIG_PCI_MSI *//* * Hypertransport interrupt support */#ifdef CONFIG_HT_IRQ#ifdef CONFIG_SMPstatic void target_ht_irq(unsigned int irq, unsigned int dest){ struct ht_irq_msg msg; fetch_ht_irq_msg(irq, &msg); msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK); msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest); msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); write_ht_irq_msg(irq, &msg);}static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask){ unsigned int dest; cpumask_t tmp; cpus_and(tmp, mask, cpu_online_map); if (cpus_empty(tmp)) tmp = TARGET_CPUS; cpus_and(mask, tmp, CPU_MASK_ALL); dest = cpu_mask_to_apicid(mask); target_ht_irq(irq, dest); irq_desc[irq].affinity = mask;}#endifstatic struct irq_chip ht_irq_chip = { .name = "PCI-HT", .mask = mask_ht_irq, .unmask = unmask_ht_irq, .ack = ack_ioapic_irq,#ifdef CONFIG_SMP .set_af
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -