📄 io_apic_32.c
字号:
continue; if (max_cpu_irq <= CPU_IRQ(i)) continue; if (tmp_cpu_irq < CPU_IRQ(i)) { tmp_cpu_irq = CPU_IRQ(i); tmp_loaded = i; } } if (tmp_loaded == -1) { /* In the case of small number of heavy interrupt sources, * loading some of the cpus too much. We use Ingo's original * approach to rotate them around. */ if (!first_attempt && imbalance >= useful_load_threshold) { rotate_irqs_among_cpus(useful_load_threshold); return; } goto not_worth_the_effort; } first_attempt = 0; /* heaviest search */ max_cpu_irq = tmp_cpu_irq; /* load */ max_loaded = tmp_loaded; /* processor */ imbalance = (max_cpu_irq - min_cpu_irq) / 2; /* if imbalance is less than approx 10% of max load, then * observe diminishing returns action. - quit */ if (imbalance < (max_cpu_irq >> 3)) goto not_worth_the_effort;tryanotherirq: /* if we select an IRQ to move that can't go where we want, then * see if there is another one to try. */ move_this_load = 0; selected_irq = -1; for (j = 0; j < NR_IRQS; j++) { /* Is this an active IRQ? */ if (!irq_desc[j].action) continue; if (imbalance <= IRQ_DELTA(max_loaded,j)) continue; /* Try to find the IRQ that is closest to the imbalance * without going over. */ if (move_this_load < IRQ_DELTA(max_loaded,j)) { move_this_load = IRQ_DELTA(max_loaded,j); selected_irq = j; } } if (selected_irq == -1) { goto tryanothercpu; } imbalance = move_this_load; /* For physical_balance case, we accumulated both load * values in the one of the siblings cpu_irq[], * to use the same code for physical and logical processors * as much as possible. * * NOTE: the cpu_irq[] array holds the sum of the load for * sibling A and sibling B in the slot for the lowest numbered * sibling (A), _AND_ the load for sibling B in the slot for * the higher numbered sibling. * * We seek the least loaded sibling by making the comparison * (A+B)/2 vs B */ load = CPU_IRQ(min_loaded) >> 1; for_each_cpu_mask(j, per_cpu(cpu_sibling_map, min_loaded)) { if (load > CPU_IRQ(j)) { /* This won't change cpu_sibling_map[min_loaded] */ load = CPU_IRQ(j); min_loaded = j; } } cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[selected_irq]); target_cpu_mask = cpumask_of_cpu(min_loaded); cpus_and(tmp, target_cpu_mask, allowed_mask); if (!cpus_empty(tmp)) { /* mark for change destination */ set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded)); /* Since we made a change, come back sooner to * check for more variation. */ balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); return; } goto tryanotherirq;not_worth_the_effort: /* * if we did not find an IRQ to move, then adjust the time interval * upward */ balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); return;}static int balanced_irq(void *unused){ int i; unsigned long prev_balance_time = jiffies; long time_remaining = balanced_irq_interval; /* push everything to CPU 0 to give us a starting point. */ for (i = 0 ; i < NR_IRQS ; i++) { irq_desc[i].pending_mask = cpumask_of_cpu(0); set_pending_irq(i, cpumask_of_cpu(0)); } set_freezable(); for ( ; ; ) { time_remaining = schedule_timeout_interruptible(time_remaining); try_to_freeze(); if (time_after(jiffies, prev_balance_time+balanced_irq_interval)) { preempt_disable(); do_irq_balance(); prev_balance_time = jiffies; time_remaining = balanced_irq_interval; preempt_enable(); } } return 0;}static int __init balanced_irq_init(void){ int i; struct cpuinfo_x86 *c; cpumask_t tmp; cpus_shift_right(tmp, cpu_online_map, 2); c = &boot_cpu_data; /* When not overwritten by the command line ask subarchitecture. */ if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) irqbalance_disabled = NO_BALANCE_IRQ; if (irqbalance_disabled) return 0; /* disable irqbalance completely if there is only one processor online */ if (num_online_cpus() < 2) { irqbalance_disabled = 1; return 0; } /* * Enable physical balance only if more than 1 physical processor * is present */ if (smp_num_siblings > 1 && !cpus_empty(tmp)) physical_balance = 1; for_each_online_cpu(i) { irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { printk(KERN_ERR "balanced_irq_init: out of memory"); goto failed; } memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); } printk(KERN_INFO "Starting balanced_irq\n"); if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd"))) return 0; printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");failed: for_each_possible_cpu(i) { kfree(irq_cpu_data[i].irq_delta); irq_cpu_data[i].irq_delta = NULL; kfree(irq_cpu_data[i].last_irq); irq_cpu_data[i].last_irq = NULL; } return 0;}int __devinit irqbalance_disable(char *str){ irqbalance_disabled = 1; return 1;}__setup("noirqbalance", irqbalance_disable);late_initcall(balanced_irq_init);#endif /* CONFIG_IRQBALANCE */#endif /* CONFIG_SMP */#ifndef CONFIG_SMPvoid fastcall send_IPI_self(int vector){ unsigned int cfg; /* * Wait for idle. */ apic_wait_icr_idle(); cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; /* * Send the IPI. The write to APIC_ICR fires this off. */ apic_write_around(APIC_ICR, cfg);}#endif /* !CONFIG_SMP *//* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. */#define MAX_PIRQS 8static int pirq_entries [MAX_PIRQS];static int pirqs_enabled;int skip_ioapic_setup;static int __init ioapic_pirq_setup(char *str){ int i, max; int ints[MAX_PIRQS+1]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i < MAX_PIRQS; i++) pirq_entries[i] = -1; pirqs_enabled = 1; apic_printk(APIC_VERBOSE, KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { apic_printk(APIC_VERBOSE, KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; } return 1;}__setup("pirq=", ioapic_pirq_setup);/* * Find the IRQ entry number of a certain pin. */static int find_irq_entry(int apic, int pin, int type){ int i; for (i = 0; i < mp_irq_entries; i++) if (mp_irqs[i].mpc_irqtype == type && (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && mp_irqs[i].mpc_dstirq == pin) return i; return -1;}/* * Find the pin to which IRQ[irq] (ISA) is connected */static int __init find_isa_irq_pin(int irq, int type){ int i; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || mp_bus_id_to_type[lbus] == MP_BUS_MCA ) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) return mp_irqs[i].mpc_dstirq; } return -1;}static int __init find_isa_irq_apic(int irq, int type){ int i; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || mp_bus_id_to_type[lbus] == MP_BUS_MCA ) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) break; } if (i < mp_irq_entries) { int apic; for(apic = 0; apic < nr_ioapics; apic++) { if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) return apic; } } return -1;}/* * Find a specific PCI IRQ entry. * Not an __init, possibly needed by modules */static int pin_2_irq(int idx, int apic, int pin);int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin){ int apic, i, best_guess = -1; apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " "slot:%d, pin:%d.\n", bus, slot, pin); if (mp_bus_id_to_pci_bus[bus] == -1) { printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; } for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; for (apic = 0; apic < nr_ioapics; apic++) if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || mp_irqs[i].mpc_dstapic == MP_APIC_ALL) break; if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == lbus) && (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); if (!(apic || IO_APIC_IRQ(irq))) continue; if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) return irq; /* * Use the first all-but-pin matching entry as a * best-guess fuzzy result for broken mptables. */ if (best_guess < 0) best_guess = irq; } } return best_guess;}EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);/* * This function currently is only a helper for the i386 smp boot process where * we need to reprogram the ioredtbls to cater for the cpus which have come online * so mask in all cases should simply be TARGET_CPUS */#ifdef CONFIG_SMPvoid __init setup_ioapic_dest(void){ int pin, ioapic, irq, irq_entry; if (skip_ioapic_setup == 1) return; for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { irq_entry = find_irq_entry(ioapic, pin, mp_INT); if (irq_entry == -1) continue; irq = pin_2_irq(irq_entry, ioapic, pin); set_ioapic_affinity_irq(irq, TARGET_CPUS); } }}#endif/* * EISA Edge/Level control register, ELCR */static int EISA_ELCR(unsigned int irq){ if (irq < 16) { unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } apic_printk(APIC_VERBOSE, KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); return 0;}/* EISA interrupts are always polarity zero and can be edge or level * trigger depending on the ELCR value. If an interrupt is listed as * EISA conforming in the MP table, that means its trigger type must * be read in from the ELCR */#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))#define default_EISA_polarity(idx) (0)/* ISA interrupts are always polarity zero edge triggered, * when listed as conforming in the MP table. */#define default_ISA_trigger(idx) (0)#define default_ISA_polarity(idx) (0)/* PCI interrupts are always polarity one level triggered, * when listed as conforming in the MP table. */#define default_PCI_trigger(idx) (1)#define default_PCI_polarity(idx) (1)/* MCA interrupts are always polarity zero level triggered, * when listed as conforming in the MP table. */#define default_MCA_trigger(idx) (1)#define default_MCA_polarity(idx) (0)static int MPBIOS_polarity(int idx){ int bus = mp_irqs[idx].mpc_srcbus; int polarity; /* * Determine IRQ line polarity (high active or low active): */ switch (mp_irqs[idx].mpc_irqflag & 3) { case 0: /* conforms, ie. bus-type dependent polarity */ { switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ { polarity = default_ISA_polarity(idx); break; } case MP_BUS_EISA: /* EISA pin */ { polarity = default_EISA_polarity(idx); break; } case MP_BUS_PCI: /* PCI pin */ { polarity = default_PCI_polarity(idx); break; } case MP_BUS_MCA: /* MCA pin */ { polarity = default_MCA_polarity(idx); break; } default: { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } } break; } case 1: /* high active */ { polarity = 0; break; } case 2: /* reserved */ { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } case 3: /* low active */ { polarity = 1; break; } default: /* invalid */ { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } } return polarity;}static int MPBIOS_trigger(int idx){ int bus = mp_irqs[idx].mpc_srcbus; int trigger; /* * Determine IRQ trigger mode (edge or level sensitive): */ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) { case 0: /* conforms, ie. bus-type dependent */ { switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ { trigger = default_ISA_trigger(idx); break; } case MP_BUS_EISA: /* EISA pin */ { trigger = default_EISA_trigger(idx); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -