- 论坛徽章:
- 0
|
- /* ===== in x86_64/kernel/apic.c ====== */
-
- static __init int setup_disableapic(char *str)
- {
- disable_apic = 1;
- /*
- * P not only in APIC, but also
- */
- clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
- return 0;
- }
- early_param("disableapic", setup_disableapic);
- /*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
- int __init APIC_init_uniprocessor(void)
- {
- if (disable_apic) {
- printk(KERN_INFO "Apic disabled\n");
- return -1;
- }
- if (!cpu_has_apic) {
- disable_apic = 1;
- printk(KERN_INFO "Apic disabled by BIOS\n");
- return -1;
- }
- verify_local_APIC();
- phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
- /*
- * 1, what cpu is in APIC space
- */
- apic_write(APIC_ID, SET_APIC_ID(boot_cpu_id));
- /*
- * 2, LAPIC first
- */
- setup_local_APIC();
- if (smp_found_config
- && !skip_ioapic_setup
- && nr_ioapics) {
- /*
- * 3, then IO APIC if at least smp_found_config
- * why??
- * maybe IRT unecessary
- */
- setup_IO_APIC();
- } else
- nr_ioapics = 0;
- /*
- * 4, and LAPIC clock
- */
- setup_boot_APIC_clock();
- /*
- * 5, finally NMI
- */
- check_nmi_watchdog();
- return 0;
- }
- asmlinkage void smp_error_interrupt(void)
- {
- unsigned int v, v1;
- exit_idle();
- irq_enter();
- /*
- First tickle the hardware,
- only then report what went on.
- -- REW
- */
- v = apic_read(APIC_ESR);
- apic_write(APIC_ESR, 0);
- v1 = apic_read(APIC_ESR);
- ack_APIC_irq();
- /*
- * and the order is important, why not???
- v = apic_read(APIC_ESR);
- apic_write(APIC_ESR, 0);
- ack_APIC_irq();
- v1 = apic_read(APIC_ESR);
- */
- atomic_inc(&irq_err_count);
- /* Here is what the APIC error bits mean:
- 0: Send CS error
- 1: Receive CS error
- 2: Send accept error
- 3: Receive accept error
- 4: Reserved
- 5: Send illegal vector
- 6: Received illegal vector
- 7: Illegal register address
- */
- printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
- smp_processor_id(), v , v1);
- irq_exit();
- }
- asmlinkage void smp_spurious_interrupt (void)
- {
- unsigned int v;
- exit_idle();
- irq_enter();
- /*
- * Check if this really is a spurious interrupt and ACK it.
- * if it is a vectored one. Just in case...
- * Spurious interrupts should not be ACKed.
- */
- v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
- if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
- ack_APIC_irq();
- /* ack should be ASAP,
- * and tell user innomarl occured,
- *
- * 八哥遇见e100-82559中断无人处理的情况,on Intel-5110,
- * 系统将其关闭。
- */
- {
- static unsigned long last_warning;
- static unsigned long skipped;
- /* see sw-dev-man vol 3, chapter 7.4.13.5 */
- /// if (time_before(last_warning+30*HZ, jiffies)) {
- if (time_before(jiffies, last_warning +30*HZ)) {
- printk(KERN_INFO
- "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
- smp_processor_id(), skipped);
- last_warning = jiffies;
- skipped = 0;
- } else {
- skipped++;
- }
- }
- irq_exit();
- }
- /*
- * LAPIC包含一个内部时钟 and operation
- */
- void enable_APIC_timer (void)
- {
- /*
- * 多数情况的应用是logic cpu number
- */
- int cpu = smp_processor_id();
- if (using_apic_timer &&
- !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
- unsigned long v;
- v = apic_read(APIC_LVTT);
- apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
- }
- }
- /*
- * goto read manul by AMD
- */
- void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
- unsigned char msg_type, unsigned char mask)
- {
- unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
- unsigned int v = (mask << 16) | (msg_type << 8) | vector;
- apic_write(reg, v);
- }
- void smp_send_timer_broadcast_ipi(void)
- {
- int cpu = smp_processor_id();
- cpumask_t mask;
- cpus_and(mask, cpu_online_map,
- timer_interrupt_broadcast_ipi_mask);
- if (cpu_isset(cpu, mask)) {
- cpu_clear(cpu, mask);
- add_pda(apic_timer_irqs, 1);
- smp_local_timer_interrupt();
- }
- /*
- * 请 cpus in mask do IRQ represented by LOCAL_TIMER_VECTOR,
- * cpu 不懂IRQ,but vector
- *
- * 这样的应用方式大有意思。
- */
- if (!cpus_empty(mask))
- send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
- }
- /*
- * 编程APIC,启用timer
- */
- void enable_APIC_timer (void)
- {
- int cpu = smp_processor_id();
- if (using_apic_timer &&
- !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
- unsigned long v;
- v = apic_read(APIC_LVTT);
- apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
- }
- }
- static int __init calibrate_APIC_clock(void)
- {
- unsigned apic, apic_start;
- unsigned long tsc, tsc_start;
- int result;
- /*
- * Put whatever arbitrary (but long enough) timeout
- * value into the APIC clock, we just want to get the
- * counter running for calibration.
- */
- __setup_APIC_LVTT(4000000000);
- apic_start = apic_read(APIC_TMCCT);
-
- #ifdef CONFIG_X86_PM_TIMER
- if (apic_calibrate_pmtmr && pmtmr_ioport) {
- pmtimer_wait(5000); /* 5ms wait */
- apic = apic_read(APIC_TMCCT);
- result = (apic_start - apic) * 1000L / 5;
- } else
- #endif
- {
- /*
- * tsc, timestamp counter,
- * 这个准一些,亚纳秒级的精度。
- */
- rdtscll(tsc_start);
- do {
- apic = apic_read(APIC_TMCCT);
- rdtscll(tsc);
- } while ((tsc - tsc_start) < TICK_COUNT &&
- (apic_start - apic) < TICK_COUNT);
- /* 得到微秒级的结果 */
- result = (apic_start - apic) * 1000L * tsc_khz /
- (tsc - tsc_start);
- }
- printk("result %d\n", result);
- printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
- result / 1000 / 1000, result / 1000 % 1000);
- return result * APIC_DIVISOR / HZ;
- }
- /*
- * This function sets up the local APIC timer,
- * with a timeout of 'clocks' APIC bus clock.
- */
- static void __setup_APIC_LVTT(unsigned int clocks)
- {
- unsigned int lvtt_value, tmp_value;
- int cpu = smp_processor_id();
- lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
- if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
- lvtt_value |= APIC_LVT_MASKED;
- apic_write(APIC_LVTT, lvtt_value);
- /*
- * Divide PICLK by 16
- * 32, 64...1024 未必不可,不过没试过。
- * 看看如何影响 Ingo Molnar的HPET
- */
- tmp_value = apic_read(APIC_TDCR);
- apic_write(APIC_TDCR,
- (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
- | APIC_TDR_DIV_16);
- apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
- }
- void __init init_apic_mappings(void)
- {
- unsigned long apic_phys;
- /*
- * If no local APIC can be found then set up a fake all
- * zeroes page to simulate the local APIC and another
- * one for the IO-APIC.
- */
- if (!smp_found_config && detect_init_APIC()) {
- apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
- apic_phys = __pa(apic_phys);
- } else /*
- * 当然是硬件的,
- * smp_found_config的由来,下回再说。
- */
- apic_phys = mp_lapic_addr;
- set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
- apic_mapped = 1;
- apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n",
- APIC_BASE, apic_phys);
- /* Put local APIC into the resource map. */
- lapic_resource.start = apic_phys;
- lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1;
- insert_resource(&iomem_resource, &lapic_resource);
- /*
- * Fetch the APIC ID of the BSP in case we have a
- * default configuration (or the MP table is broken).
- *
- * 对应smp_processor_id
- */
- boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
- {
- unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
- int i;
- struct resource *ioapic_res;
- ioapic_res = ioapic_setup_resources();
- for (i = 0; i < nr_ioapics; i++) {
- if (smp_found_config) {
- ioapic_phys = mp_ioapics[i].mpc_apicaddr;
- } else {
- ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
- ioapic_phys = __pa(ioapic_phys);
- }
- set_fixmap_nocache(idx, ioapic_phys);
- apic_printk(APIC_VERBOSE,
- "mapped IOAPIC to %016lx (%016lx)\n",
- __fix_to_virt(idx), ioapic_phys);
- idx++;
- if (ioapic_res != NULL) {
- ioapic_res->start = ioapic_phys;
- ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
- ioapic_res++;
- }
- }
- }
- }
- static int lapic_suspend(struct sys_device *dev, pm_message_t state);
- /*
- * 变化真快,LAPIC也睡觉,
- * 还是请球王alb讲讲ACPI
- */
- static int lapic_resume(struct sys_device *dev)
- void __cpuinit setup_local_APIC (void)
- {
- unsigned int value, maxlvt;
- int i, j;
- value = apic_read(APIC_LVR);
- BUILD_BUG_ON((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f);
- /*
- * Double-check whether this APIC is really registered.
- * This is meaningless in clustered apic mode, so we skip it.
- */
- if (!apic_id_registered())
- BUG();
- /*
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116). So here it goes...
- */
- init_apic_ldr();
- /*
- * Set Task Priority to 'accept all'.
- * We never change this later on.
- *
- * 其一,linux 处理LAPIC与IOAPIC的关系如此简单,
- * 这是主要关系
- */
- value = apic_read(APIC_TASKPRI);
- value &= ~APIC_TPRI_MASK;
- apic_write(APIC_TASKPRI, value);
- /*
- * After a crash, we no longer service the interrupts and a pending
- * interrupt from previous kernel might still have ISR bit set.
- *
- * Most probably by now CPU has serviced that pending interrupt and
- * it might not have done the ack_APIC_irq() because it thought,
- * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
- * does not clear the ISR bit and cpu thinks it has already serivced
- * the interrupt. Hence a vector might get locked. It was noticed
- * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
- */
- for (i = APIC_ISR_NR - 1; i >= 0; i--) {
- value = apic_read(APIC_ISR + i*0x10);
- for (j = 31; j >= 0; j--) {
- if (value & (1<<j))
- ack_APIC_irq();
- }
- }
- /*
- * Now that we are all set up, enable the APIC
- */
- value = apic_read(APIC_SPIV);
- value &= ~APIC_VECTOR_MASK;
- /*
- * Enable APIC
- */
- value |= APIC_SPIV_APIC_ENABLED;
- /* We always use processor focus */
- /*
- * Set spurious IRQ vector
- */
- value |= SPURIOUS_APIC_VECTOR;
- apic_write(APIC_SPIV, value);
- /*
- * Set up LVT0, LVT1:
- *
- * set up through-local-APIC on the BP's LINT0. This is not
- * strictly necessary in pure symmetric-IO mode, but sometimes
- * we delegate interrupts to the 8259A.
- */
- /*
- * TODO: set up through-local-APIC from through-I/O-APIC? --macro
- */
- value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
- if (!smp_processor_id() && !value) {
- value = APIC_DM_EXTINT;
- apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
- } else {
- value = APIC_DM_EXTINT | APIC_LVT_MASKED;
- apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
- }
- apic_write(APIC_LVT0, value);
- /*
- * only the BP should see the LINT1 NMI signal, obviously.
- */
- if (!smp_processor_id())
- value = APIC_DM_NMI;
- else
- value = APIC_DM_NMI | APIC_LVT_MASKED;
- apic_write(APIC_LVT1, value);
- {
- unsigned oldvalue;
-
- maxlvt = get_maxlvt();
- oldvalue = apic_read(APIC_ESR);
- value = ERROR_APIC_VECTOR; // enables sending errors
- apic_write(APIC_LVTERR, value);
- /*
- * spec says clear errors after enabling vector.
- */
- if (maxlvt > 3)
- apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- if (value != oldvalue)
- apic_printk(APIC_VERBOSE,
- "ESR value after enabling vector: %08x, after %08x\n",
- oldvalue, value);
- }
- nmi_watchdog_default();
- setup_apic_nmi_watchdog(NULL);
- apic_pm_activate();
- }
- void __init init_bsp_APIC(void)
- {
- unsigned int value;
- /*
- * Don't do the setup now if we have a SMP BIOS as the
- * through-I/O-APIC virtual wire mode might be active.
- */
- if (smp_found_config || !cpu_has_apic)
- return;
- value = apic_read(APIC_LVR);
- /*
- * Do not trust the local APIC being empty at bootup.
- */
- clear_local_APIC();
- /*
- * Enable APIC.
- */
- value = apic_read(APIC_SPIV);
- value &= ~APIC_VECTOR_MASK;
- value |= APIC_SPIV_APIC_ENABLED;
- /*
- * 其二,BSP不用FOCUS
- */
- value |= APIC_SPIV_FOCUS_DISABLED;
- value |= SPURIOUS_APIC_VECTOR;
- apic_write(APIC_SPIV, value);
- /*
- * Set up the virtual wire mode.
- */
- apic_write(APIC_LVT0, APIC_DM_EXTINT);
- value = APIC_DM_NMI;
- apic_write(APIC_LVT1, value);
- }
- void __init sync_Arb_IDs(void)
- {
- /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
- unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
-
- /* P4 or higher
- * Intel 关于SMP的1.4版本
- */
- if (ver >= 0x14)
- return;
- /*
- * Wait for idle.
- */
- apic_wait_icr_idle();
- apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
- /*
- * 其三,仲裁机制的使用
- */
- apic_write(APIC_ICR, APIC_DEST_ALLINC |
- APIC_INT_LEVELTRIG
- | APIC_DM_INIT);
- }
复制代码 |
|